免费 网站源码,产品免费发布平台,网站模板 百科,建设网站选题应遵循的规则DI依赖注入
声明了一个成员变量#xff08;对象#xff09;之后#xff0c;在该对象上面加上注解AutoWired注解#xff0c;那么在程序运行时#xff0c;该对象自动在IOC容器中寻找对应的bean对象#xff0c;并且将其赋值给成员变量#xff0c;完成依赖注入。
AutoWire…DI依赖注入
声明了一个成员变量对象之后在该对象上面加上注解AutoWired注解那么在程序运行时该对象自动在IOC容器中寻找对应的bean对象并且将其赋值给成员变量完成依赖注入。
AutoWired依赖注入的常见方式
1.属性注入
直接使用AutoWired进行属性注入
Autowired
private UserService userService;这是最简单的依赖注入方式其优点是代码简洁可以方便快速的开发。其缺点是直接使用属性注入隐藏了各类之间的依赖关系Controller是依赖了Service的但是在类的结构层面无法看出二者的关联。还有可能会破坏类的封装性按照封装性的解释来看我们需要将成员属性设置为私有并对外提供对应的set/get方法但是直接使用属性注入没有对外提供set方法直接对其赋值在底层是通过反射对其进行赋值的实际上是破坏了面向对象的封装性原则的。
2.构造函数注入
通过构造函数的方式完成对成员变量的依赖注入
private final UserService userService;
Autowired
public UserController(UserService userService) {this.userService userService;
}相对于属性注入而言构造函数注入就能够清晰的看到各类之间的依赖关系并且基于构造函数注入可以将userService设置为final更加安全。但是假如是该类依赖了多个其他的类都交给IOC容器管理那么在书写构造方法注入的时候构造方法的参数将十分多构造方法将十分臃肿。
注意如果该类只有一个构造函数那么该构造函数上的Autowired注解可以省略
3.setter注入
通过set方法完成对成员变量的依赖注入
private UserService userService;
Autowired
public void setUserService(UserService userService) {this.userService userService;
}优点和构造方法注入类似但是不能将成员变量设置为final缺点是需要额外提供set方法编码繁琐。这种setter注入在开发中基本上不会使用。
在项目开发中Spring官方推荐构造函数注入因为其很好的保证了面向对象的特性并且安全性得到很好的保障但是在开发中大部分项目都喜欢使用属性注入因为其简洁、方便开发。所以说要根据项目的具体要求而判断在简洁性和规范性之间进行取舍。setter注入基本不用
使用AutoWired注解的注意事项
类型注入
Autowired注解在进行依赖注入时默认是依据类型进行注入操作。然而倘若存在需要注入的对象有多个对应的 bean实例时就会引发错误
这是第一个UserService的bean
package com.wzb.service.impl;import com.wzb.dao.UserDao;
import com.wzb.pojo.User;
import com.wzb.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.stream.Collectors;/*** Service层实现类**/
Component(newName)
public class UserServiceImpl implements UserService {Autowiredprivate UserDao userDao;// 获取用户数据的代码不能写在此处类的成员变量初始化是在类的实例化阶段进行的此时可能AutoWired注入还未完成导致Null// private final ListString lines userDao.findUser();public ListUser findUser() {ListString lines userDao.findUser();ListUser userList lines.stream().map(line - {String[] parts line.split(,);Integer id Integer.parseInt(parts[0]);String username parts[1];String password parts[2];String name parts[3];Integer age Integer.parseInt(parts[4]);LocalDateTime updateTime LocalDateTime.parse(parts[5], DateTimeFormatter.ofPattern(yyyy-MM-dd HH:mm:ss));return new User(id, username, password, name, age, updateTime);}).collect(Collectors.toList());return userList;}
}这是第二个UserService对象的bean
package com.wzb.service.impl;import com.wzb.dao.UserDao;
import com.wzb.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.stream.Collectors;/*** 用于测试用的bean* */
Component
public class UserServiceImpl2 implements UserService{Autowiredprivate UserDao userDao;public ListUser findUser() {ListString lines userDao.findUser();ListUser userList lines.stream().map(line - {String[] parts line.split(,);Integer id Integer.parseInt(parts[0]) 200;String username parts[1];String password parts[2];String name parts[3];Integer age Integer.parseInt(parts[4]);LocalDateTime updateTime LocalDateTime.parse(parts[5], DateTimeFormatter.ofPattern(yyyy-MM-dd HH:mm:ss));return new User(id, username, password, name, age, updateTime);}).collect(Collectors.toList());return userList;}
}此时Controller中需要依赖UserService这个类但是IOC容器中有两个这个对象的bean此时如果直接启动程序将会直接报错 报错信息 根据报错信息的描述来看是因为UserController需要一个bean也就是UserService的实现类但是在IOC容器中找到了两个该对象的bean实例不知道应该注入哪一个所以说就报错了。并且还在Action中提供了一个解决方法使用Primary、Qualifier注解。这证明了不能直接将同一个对象的多个bean加入IOC容器管理如果一个对象有多个bean都需要给IOC容器管理那么就需要使用其他注解来成功找到需要的bean并注入。
解决方法
Primary
假如需要注入的对象在IOC容器中存在多个bean实例那么就可以在想要被注入的bean上添加注解Primary 使用Primary注解指定注入的UserService bean实例是UserServiceImpl2将服务启动结合前端页面查看结果 发现用户的id都加了200说明此时注入的UserService实例bean是UserServiceImpl2Primary注解成功指定了注入的bean实例。
Qualifier
Qualifier注解需要配合AutoWired注解使用Qualifier注解是在声明对象时使用可以通过注解名默认是类名小写指定需要注入的bean实例对象。
通过Qualifier注解和AutoWired注解结合使用指定需要注入UserService的bean实例是UserServiceImpl注意bean名字是类名小写: 发现通过Qualifier注解和AutoWired注解结合使用成功将UserService需要注入的bean实例指定为了UserServiceImpl。
重要一点
此时UserServiceImpl2上面的Primary注解还在但是注入的是UserServiceImpl说明Qualifiler的优先级高于Primary。
Resource
Resource注解是在声明对象时使用单独使用通过注解名指定需要注入的bean实例 Resource注解不是Spring提供的是JavaEE规范中提供的使用时需要指定name bean名同样此时UserServiceImpl2的Primary注解还在但是注入的是Resource注解指定的bean实例所以说Resource注解的优先级也高于Primary注解。
但是假如将Resource和Qualifier注解一起用 其注入的bean是Resource注解指定的说明Resource的优先级高于Qualifier可能是因为原生JavaEE的优先级高于SpringBoot框架的缘故。
Resource和AutoWired都可以实现依赖注入其二者区别主要有两点1.AutoWired是Spring框架提供的而Resource是JavaEE提供的二者的出处不同2.AutoWired是默认按照类型注入的但Resource是默认按照bean的名称进行注入的。
总的而言假如说一个类在IOC容器中存在多个bean实例那么无法直接使用因为不知道该选择哪个bean进行注入需要添加注解指定需要注入哪个bean。