获取 bean 对象也叫做对象装配,是把对象取出来放到某个类中,有时候也叫对象注入
对象装配(对象注入)的实现方法以下 3 种:
- 属性注入
- 构造方法注入
- Setter 注入
接下来,我们分别来看,下面我们按照实际开发中的模式,将 Service类注⼊到Controller类中
Spring的注入方式
- 属性注入
- setter注入
- 构造方法注入
- 三种注入方式对比
公共类:
package com.bit.Model;
/**
* 表示一个实体类,不存在Spring当中
*/
public class User {
private int id;
private String name;
private int age;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
'}';
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:content="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<content:component-scan base-package="com.bit">
</content:component-scan>
</beans>
属性注入
属性注⼊是使⽤ @Autowired
实现的,将 Service 类注⼊到 Controller 类中:
package com.bit.controller;
import com.bit.Model.User;
import com.bit.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
@Controller//将当前的类注册(存储)到Spring中
public class UserController {
//属性注入(注册),从Spring当中获取一个对象,并注入到当前类
@Autowired
private UserService userService;
public User findUserById(Integer id){//根据用户id查询用户对象
/**
* 前端传送的数据会首先通过控制器,我们可以用Integer类型接收,这样即便用户提供一个null值,程序也不会报错了,大不了我们自己判空.
* 而在service中可以写id,因为我们在controller中已经判空了
*/
if(null==id){
//无效参数
return new User();//返回一个空的User对象
}
return userService.findUserById(id);
}
}
package com.bit.service;
import com.bit.Model.User;
import org.springframework.stereotype.Service;
@Service//将当前的对象存储到Spring
public class UserService {
/**
*根据用户的id获取用户的对象
* @param id
* @return
*/
public User findUserById(int id){//id为int类型和Integer类型的都可以
//伪代码查询数据库,返回用户对象
User user=new User();
if(id==1){
user.setId(1);
user.setName("张三");
user.setAge(18);
}else{
user.setId(2);
user.setName("李四");
user.setAge(20);
}
return user;
}
}
package com.bit;
import com.bit.Model.User;
import com.bit.controller.UserController;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
*Spring启动类,非必需的,只是为了方便演示Spring的功能而创建的
*/
public class App {
public static void main(String[] args) {
//先获取对象
ApplicationContext context=new ClassPathXmlApplicationContext("spring.xml");
//得到UserController对象
UserController controller=context.getBean("userController",UserController.class);
//调用UserController里面的findUserById查询用户信息
User user=controller.findUserById(1);
//打印对象
System.out.println(user);
}
}
打印结果如下:
setter注入
Setter 注⼊和属性的 Setter 方法实现类似,只不过在设置 set 方法的时候需要加上 @Autowired
注解。有以下三步:
定义完属性后,我们在编译期中可以自动按照如上方式生成setter方法。其余代码如下:
package com.bit.controller;
import com.bit.Model.User;
import com.bit.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
@Controller
public class UserController2 {
//1.将UserService注入到当前类【使用setter注入的方法注入】
private UserService userService;
@Autowired//必须要添加的注解
public void setUserService(UserService userService) {
this.userService = userService;
}
//2.新建一个方法,在方法里面调用UserService的查询方法,返回用户对象
public User findUserById(Integer id){
return userService.findUserById(id);
}
}
package com.bit;
import com.bit.Model.User;
import com.bit.controller.UserController;
import com.bit.controller.UserController2;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
*Spring启动类,非必需的,只是为了方便演示Spring的功能而创建的
*/
public class App {
public static void main(String[] args) {
//1.先获取对象
ApplicationContext context=new ClassPathXmlApplicationContext("spring.xml");
//得到UserController对象
UserController2 controller2=context.getBean("userController2", UserController2.class);
//调用UserController里面的findUserById查询用户信息
User user=controller2.findUserById(1);
//打印对象
System.out.println(user);
}
我们需要注意,在setter注入里面,setter方法不能省略@Autowired
注解,否则就会注入失败
构造方法注入
构造⽅法注⼊是在类的构造方法中实现注入
同样,我们可以如上所示生成构造方法。其余代码如下所示:
package com.bit.controller;
import com.bit.Model.User;
import com.bit.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
@Controller
public class UserController3 {
//使用构造方法注入对象(方式3)
private UserService userService;
@Autowired//如果当前类里面只有一个构造方法,那么此注解是可以被省略的
public UserController3(UserService userService) {
this.userService = userService;
}
/**
* 根据用户id查询用户对象的方法
* @param id
* @return
*/
public User findUserById(Integer id){
return userService.findUserById(id);
}
}
注意事项:如果当前类里面只有一个构造方法,那么@Autowired
这个注解是可以省略的,这点和setter注入是不一样的
三种注入方式对比
- 属性注⼊的优点是简洁,使用方便;缺点是只能用于 IoC 容器,如果是非 IoC 容器不可用,并且只有在使用的时候才会出现 NPE(空指针异常)。
- 构造方法注入是 Spring 推荐的注入方式,它的缺点是如果有多个注⼊会显得比较臃肿,但出现这种情况你应该考虑⼀下当前类是否符合程序的单⼀职责的设计模式了。它的优点是通用性较强,不管是什么语言,构造方法的写法基本是类似的,而setter的写法很可能就不一样了,且在使用之前⼀定能把保证注⼊的类不为空。
- Setter 方式是 Spring 前期版本推荐的注入方式,但通用性不如构造方法,所有 Spring 现版本已经推荐使用构造方法注入的方式来进行类注⼊了