属性注入的三种方式
为了简便开发Spring给我们提供了多样化的注入: @Value
注解可以出现在属性上,setter方法上以及构造方法的形参上
在简单类型的属性上
使用@Value注解完成属性值的注入(可以不提供属性的setter方法)
@Component
public class User {
@Value(value = "zhangsan")
private String name;
@Value("20")
private int age;
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
在简单类型属性对应的setter方法上
添加@Value注解完成注入
@Component
public class User {
private String name;
private int age;
@Value("李四")
public void setName(String name) {
this.name = name;
}
@Value("30")
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
在简单类型属性所在的构造方法的形参上
添加@Value注解完成注入
@Component
public class User {
private String name;
private int age;
public User(@Value("张三") String name, @Value("33") int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
测试程序简单类型的注入
@Test
public void testAutowired(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-di-annotation.xml");
UserService userService = applicationContext.getBean("user", UserService.class);
System.out.println(user);
}
@Autowired注解的应用
@Autowired自动装配注解可以用来注入非简单类型, 单独使用时默认是根据类型进行注入的,若要根据名称注入的话需要配合@Qualifier注解一起使用
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {
boolean required() default true;
}
@Autowired注解的required属性
属性值 | 说明 |
---|---|
required=true(默认) | 自动注入的时候要求被注入的Bean必须是存在的,如果不存在则报错 |
required=false | 允许某一属性不被设置 , 自动注入的时候Bean存在或者不存在都没关系,存在的话就注入不存在的话也不报错 |
属性注入的几种方式
Dao接口及其实现类
//UserDao接口
public interface UserDao {
void insert();
}
//UserDao实现类
@Repository
public class UserDaoForMySQL implements UserDao{
@Override
public void insert() {
System.out.println("正在向mysql数据库插入User数据");
}
}
//UserDao接口的另一个实现类
@Repository
public class UserDaoForOracle implements UserDao{
@Override
public void insert() {
System.out.println("正在向Oracle数据库插入User数据");
}
}
在非简单类型的属性
上使用@Autowired注解完成属性值的注入(可以不提供属性的setter方法)
自定义属性UserDao时
自动注入时会报错(提示Bean的数量大于1)@Service
public class UserService {
// 自动注入属性
@Autowired
private UserDao userDao;
// 没有提供构造方法和setter方法
public void save(){
userDao.insert();
}
}
在非简单类型属性对应的setter方法
上使用@Autowired注解完成属性的自动注入
@Service
public class UserService {
private UserDao userDao;
@Autowired
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void save(){
userDao.insert();
}
}
在非简单类型属性所在的构造方法
上使用@Autowired注解完成属性的自动注入
@Service
public class UserService {
private UserDao userDao;
@Autowired
public UserService(UserDao userDao) {
this.userDao = userDao;
}
public void save(){
userDao.insert();
}
}
在非简单类型对应的构造方法的形参
上使用@Autowired注解完成属性的自动注入
@Service
public class UserService {
private UserDao userDao;
public UserService(@Autowired UserDao userDao) {
this.userDao = userDao;
}
public void save(){
userDao.insert();
}
}
测试程序
@Test
public void testAutowired(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-injection.xml");
UserService userService = applicationContext.getBean("userService", UserService.class);
userService.save();
}
省略@Autowired注解
当构造方法只有一个并且构造方法的形参名和对象的属性名能够对应上
时@Autowired注解可以省略,如果有多个构造方法就不能省略
@Service
public class UserService {
private UserDao userDao;
// 构造方法的参数只有一个时,自动注入时@Autowired注解可以省略
public UserService(UserDao userDao) {
this.userDao = userDao;
}
public void save(){
userDao.insert();
}
}
属性/方法形参注入的原理
@Autowired注解是根据类型进行自动装配的,所有可能找到多个或者一个
属性注入: Spring从容器查找组件时先按照属性的类型(可能找到一个或多个bean,也可能没找到bean),若找到多个会将属性名作为id继续匹配到某个具体的bean
找到且只有一个组件
,直接为对象的属性赋值没有找到组件
则报NoSuchBeanDefinitionException
异常找到了多个bean
则会按照属性名作为id继续匹配到某个具体的bean , 找到则会为该属性赋值 ,如果根据id还是找不到则会报错
方法形参的注入: Spring从容器中找到对应的组件为方法上的每一个形参赋值,注入原理和属性注入原理一样
属性注入的几种方式
@Autowired注解和@Qualifier注解联合
起来才可以根据名称进行装配,在@Qualifier注解中指定要查找的Bean名称(SpringMVC常用)
@Qualifier注解
里指定一个字符串作为bean的Id
去容器中匹配对应名称的bean,找到则为对象的属性自动装配,再找不到还报错Dao层的UserDao接口及其实现类
public interface UserDao {
void insert();
}
@Repository
public class UserDaoForMySQL implements UserDao{
@Override
public void insert() {
System.out.println("正在向mysql数据库插入User数据");
}
}
@Repository
public class UserDaoForOracle implements UserDao{
@Override
public void insert() {
System.out.println("正在向Oracle数据库插入User数据");
}
}
在非简单类型的属性上
额外添加@Qualifier注解指定bean的Id(默认按照属性名)
去容器中匹配对应名称的bean完成对象属性的自动装配
@Service
public class UserService {
// 自动注入属性
@Autowired
@Qualifier("userDaoForOracle")
private UserDao userDao;
// 没有提供构造方法和setter方法
public void save(){
userDao.insert();
}
}
在非简单类型属性对应的setter方法
上额外添加@Qualifier注解指定bean的Id(默认按方法形参的变量名)
去容器中匹配对应名称的bean完成对象属性的自动装配
@Service
public class UserService {
private UserDao userDao;
@Autowired
// 指定要查找的bean的名称
@Qualifier("userDaoForOracle")
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void save(){
userDao.insert();
}
}
在非简单类型属性所在方法的形参中
额外添加@Qualifiter注解指定bean的Id(默认按照形参的变量名)
去容器中匹配对应名称的bean完成对象属性的自动装配
@Autowired
public void setUserDao(@Qualifier("userDaoForOracle") UserDao userDao ) {
// 容器启动时候bean对象就会被创建,那么这个方法也会自动运行
System.out.println(bookDao);
System.out.println(bookService);
}
@Resource和@Autowired的区别
来源的区别
JDK扩展包
属于JDK的一部分,所以该注解是标准注解更加具有通用性(JSR-250标准中制定的注解类型, JSR是Java规范提案)Spring框架
自己的注入方式的区别
@Resource注解根据名称装配
: 默认使用标注处的属性名/形参名作为bean的Id去匹配bean,如果找不到还会通过类型装配但要求这种类型的Bean只能有一个@Autowired注解根据类型装配
: 默认根据标注处的属性名/形参名的类型去匹配bean,如果想根据名称装配需要配合@Qualifier注解一起用注解的作用范围不同
@Resource注解属于JDK扩展包所以不在JDK当中需要额外引入jakarta.annotation-api依赖(高于JDK11或低于JDK8需要引入以下依赖)
<dependency>
<groupId>jakarta.annotationgroupId>
<artifactId>jakarta.annotation-apiartifactId>
<version>2.1.1version>
dependency>
<dependency>
<groupId>javax.annotationgroupId>
<artifactId>javax.annotation-apiartifactId>
<version>1.3.2version>
dependency>
属性注入的几种方式
在属性上使用Resource注解根据指定的bean的Id
去容器中匹配对应的bean为属性自动装配
//给UserDao接口的实现类UserDaoForOracle起名xyz
@Repository("xyz")
public class UserDaoForOracle implements UserDao{
@Override
public void insert() {
System.out.println("正在向Oracle数据库插入User数据");
}
}
@Service
public class UserService {
@Resource(name = "xyz")
private UserDao userDao;
public void save(){
userDao.insert();
}
}
在属性上使用Resource注解根据默认的bean的Id(属性名/形参名)
去容器中匹配对应的bean为属性自动装配
//指定UserDaoForOracle的名字为userDao,让这个Bean的名字和UserService类中的UserDao属性名一致
@Repository("userDao")
public class UserDaoForOracle implements UserDao{
@Override
public void insert() {
System.out.println("正在向Oracle数据库插入User数据");
}
}
@Service
public class UserService {
//当使用@Resource注解时没有指定name属性的时候,会把属性名当作bean的Id去容器中匹配对应的bean为属性自动装配
@Resource
private UserDao userDao;
public void save(){
userDao.insert();
}
}
在属性上
使用Resource注解根据类型注入属性值
,当通过bean的Id找不到对应bean的时候也会按照属性的类型进行注入(要求该类型的bean只要一个否则报错)
@Service
public class UserService {
//UserService的属性名修改为userDao2
@Resource
private UserDao userDao2;
public void save(){
userDao2.insert();
}
}
在属性对应的setter方法
上使用@Resource注解根据默认的bean的Id(属性名/形参名)
属性自动装配(setter方法去掉set之后首字母变小写就是bean的Id)
//指定UserDaoForOracle的名字为userDao
@Repository("userDao")
public class UserDaoForOracle implements UserDao{
@Override
public void insert() {
System.out.println("正在向Oracle数据库插入User数据");
}
}
@Service
public class UserService {
private UserDao userDao;
@Resource
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void save(){
userDao.insert();
}
}
在属性对应的setter方法上
使用@Resource注解指定bean的Id
去容器中匹配对应的bean为属性自动装配
@Repository
public class UserDaoForMySQL implements UserDao{
@Override
public void insert() {
System.out.println("正在向mysql数据库插入User数据");
}
}
@Service
public class UserService {
private UserDao userDao;
@Resource(name = "userDaoForMySQL")
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void save(){
userDao.insert();
}
}