1.@Autowired、@Qualifier、@Primary注解
1.1.@Autowired注解
@Autowired注解可以对类成员变量、方法和构造函数进行标注,完成自动装配的工作。
package org.springframework.beans.factory.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {
boolean required() default true;
}
@Autowired注解说明:
- @Autowired注解默认是优先按照类型去容器中找对应的组件,若找到则就赋值,相当于是调用了如下这个方法:
applicationContext.getBean(类名.class);
- 如果找到多个相同类型的组件,那么是将属性名称作为组件的id,到IOC容器中进行查找,这时就相当于是调用了如下这个方法:
applicationContext.getBean("组件的id");
1.2.@Qualifier注解
@Autowired是根据类型进行自动装配的,如果需要按名称进行装配,那么就需要配合@Qualifier注解来使用了。
@Qualifier注解的源码,如下所示:
package org.springframework.beans.factory.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Qualifier {
String value() default "";
}
1.3.@Primary注解
在Spring中使用注解时,常常会使用到@Autowired这个注解,它默认是根据类型Type来自动注入的。但有些特殊情况,对同一个接口而言,可能会有几种不同的实现类,而在默认只会采取其中一种实现的情况下,就可以使用@Primary注解来标注优先使用哪一个实现类。
package org.springframework.context.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Primary {
}
2.自动装配
Spring组件的自动装配就是Spring利用依赖注入,也就是我们通常所说的DI,完成对IOC容器中各个组件的依赖关系赋值。
3.程序案例
3.1.测试@Autowired注解
3.1.1.测试1
创建BookDao、BookService、BookServiceImpl和BookController
- BookDao
package com.tianxia.springannotation.dao; import org.springframework.stereotype.Repository; /** * BookDao * @author liqb * @date 2023-04-21 16:37 **/ // 名字默认是类名首字母小写 @Repository public class BookDao { }
- BookService
package com.tianxia.springannotation.service; /** * BookService * @author liqb * @date 2023-04-21 16:38 **/ public interface BookService { }
- BookServiceImpl
package com.tianxia.springannotation.service.impl; import com.tianxia.springannotation.dao.BookDao; import com.tianxia.springannotation.service.BookService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; /** * BookServiceImpl * @author liqb * @date 2023-04-21 16:38 **/ @Service public class BookServiceImpl implements BookService { @Autowired private BookDao bookDao; /** * 打印方法 * @author liqb * @date 2023-05-06 13:09 */ public void print() { System.out.println(bookDao); } @Override public String toString() { return "BookService [bookDao=" + bookDao + "]"; } }
- BookController
package com.tianxia.springannotation.controller; import com.tianxia.springannotation.service.BookService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; /** * BookController * @author liqb * @date 2023-04-21 16:39 **/ @Controller public class BookController { @Autowired private BookService bookService; }
为了更好的看到效果,在项目的config包下创建MainConfigOfAutowired配置类,如下所示:
package com.tianxia.springannotation.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
/**
* 配置类
* @author liqb
* @date 2023-05-06 13:11
**/
@Configuration
@ComponentScan({"com.tianxia.springannotation.service", "com.tianxia.springannotation.dao", "com.tianxia.springannotation.controller"})
public class MainConfigOfAutowired {
}
运行测试方法,输出结果如下所示:
/**
* 测试方法
* @author liqb
* @date 2023-05-06 13:14
*/
@Test
public void test01() {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfAutowired.class);
BookService bookService = applicationContext.getBean(BookService.class);
System.out.println(bookService);
BookDao bookDao = applicationContext.getBean(BookDao.class);
System.out.println(bookDao);
applicationContext.close();
}
BookService类中使用@Autowired注解注入的BookDao对象和直接从IOC容器中获取的BookDao对象是同一个对象
3.1.2.测试2
在Spring容器中存在对多个BookDao对象,那么这时又该如何处理
对BookDao类进行改造,为其加上一个lable字段,并为其赋一个默认值,如下所示。
package com.tianxia.springannotation.dao;
import org.springframework.stereotype.Repository;
/**
* BookDao
* @author liqb
* @date 2023-04-21 16:37
**/
// 名字默认是类名首字母小写
@Repository
public class BookDao {
private String lable = "1";
public String getLable() {
return lable;
}
public void setLable(String lable) {
this.lable = lable;
}
@Override
public String toString() {
return "BookDao [lable=" + lable + "]";
}
}
在MainConfigOfAutowired配置类中注入一个BookDao对象,并且显示指定该对象在IOC容器中的bean的名称为bookDao2,并还为该对象的lable字段赋值为2
package com.tianxia.springannotation.config;
import com.tianxia.springannotation.dao.BookDao;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
/**
* 配置类
* @author liqb
* @date 2023-05-06 13:11
**/
@Configuration
@ComponentScan({"com.tianxia.springannotation.service", "com.tianxia.springannotation.dao", "com.tianxia.springannotation.controller"})
public class MainConfigOfAutowired {
/**
* 注入bookDao对象
* @author liqb
* @date 2023-05-06 13:27
* @return
*/
@Bean("bookDao2")
public BookDao bookDao() {
BookDao bookDao = new BookDao();
bookDao.setLable("2");
return bookDao;
}
}
运行测试方法,输出结果如下所示:
/**
* 测试方法
* @author liqb
* @date 2023-05-06 13:14
*/
@Test
public void test01() {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfAutowired.class);
BookService bookService = applicationContext.getBean(BookService.class);
System.out.println(bookService);
applicationContext.close();
}
结果信息输出了lable=1,说明,@Autowired注解默认是优先按照类型去容器中找对应的组件,找到就赋值;如果找到多个相同类型的组件,那么再将属性的名称作为组件的id,到IOC容器中进行查找。
让@Autowired注解装配bookDao2
将BookService类中的bookDao属性的名称全部修改为bookDao2即可,如下所示:
package com.tianxia.springannotation.service.impl;
import com.tianxia.springannotation.dao.BookDao;
import com.tianxia.springannotation.service.BookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* BookServiceImpl
* @author liqb
* @date 2023-04-21 16:38
**/
@Service
public class BookServiceImpl implements BookService {
@Autowired
private BookDao bookDao2;
/**
* 打印方法
* @author liqb
* @date 2023-05-06 13:09
*/
public void print() {
System.out.println(bookDao2);
}
@Override
public String toString() {
return "BookService [bookDao=" + bookDao2 + "]";
}
}
运行测试方法,输出结果如下所示:
结论:@Autowired注解默认是优先按照类型去容器中找对应的组件,找到就赋值;如果找到多个相同类型的组件,那么再将属性的名称作为组件的id,到IOC容器中进行查找。
3.1.3.测试3
@Autowired注解属性required
required=false这个玩意的意思就是说找到就装配,找不到就拉到,就别装配了
require= true,未找到相应的bean对象,Spring就会抛出了异常
package com.tianxia.springannotation.service.impl;
import com.tianxia.springannotation.dao.BookDao;
import com.tianxia.springannotation.service.BookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* BookServiceImpl
* @author liqb
* @date 2023-04-21 16:38
**/
@Service
public class BookServiceImpl implements BookService {
@Autowired(required = false)
private BookDao bookDao2;
/**
* 打印方法
* @author liqb
* @date 2023-05-06 13:09
*/
public void print() {
System.out.println(bookDao2);
}
@Override
public String toString() {
return "BookService [bookDao=" + bookDao2 + "]";
}
}
3.2.测试@Qualifier注解
显示指定@Autowired注解装配哪个组件
package com.tianxia.springannotation.service.impl;
import com.tianxia.springannotation.dao.BookDao;
import com.tianxia.springannotation.service.BookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
/**
* BookServiceImpl
* @author liqb
* @date 2023-04-21 16:38
**/
@Service
public class BookServiceImpl implements BookService {
@Autowired
@Qualifier("bookDao")
private BookDao bookDao2;
/**
* 打印方法
* @author liqb
* @date 2023-05-06 13:09
*/
public void print() {
System.out.println(bookDao2);
}
@Override
public String toString() {
return "BookService [bookDao=" + bookDao2 + "]";
}
}
运行测试方法,输出结果如下所示:
此时尽管字段的名称为bookDao2,但是使用了@Qualifier注解显示指定了@Autowired注解装配bookDao对象,所以,最终的结果中输出了bookDao对象的信息。
3.3.测试@Primary注解
在Spring中,对同一个接口而言,可能会有几种不同的实现类,而默认只会采取其中一种实现的情况下,就可以使用@Primary注解来标注优先使用哪一个实现类。
在MainConfigOfAutowired配置类的bookDao()方法上添加上@Primary注解,如下所示:
package com.tianxia.springannotation.config;
import com.tianxia.springannotation.dao.BookDao;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
/**
* 配置类
* @author liqb
* @date 2023-05-06 13:11
**/
@Configuration
@ComponentScan({"com.tianxia.springannotation.service", "com.tianxia.springannotation.dao", "com.tianxia.springannotation.controller"})
public class MainConfigOfAutowired {
/**
* 注入bookDao对象
* @author liqb
* @date 2023-05-06 13:27
* @return
*/
@Primary
@Bean("bookDao2")
public BookDao bookDao() {
BookDao bookDao = new BookDao();
bookDao.setLable("2");
return bookDao;
}
}
注释掉BookService类中bookDao字段上的@Qualifier注解
package com.tianxia.springannotation.service.impl;
import com.tianxia.springannotation.dao.BookDao;
import com.tianxia.springannotation.service.BookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
/**
* BookServiceImpl
* @author liqb
* @date 2023-04-21 16:38
**/
@Service
public class BookServiceImpl implements BookService {
// @Qualifier("bookDao")
@Autowired(required = false)
private BookDao bookDao2;
/**
* 打印方法
* @author liqb
* @date 2023-05-06 13:09
*/
public void print() {
System.out.println(bookDao2);
}
@Override
public String toString() {
return "BookService [bookDao=" + bookDao2 + "]";
}
}
运行测试方法,输出结果如下所示:
此时lable的值为2,这说明装配了MainConfigOfAutowired配置类中注入的bookDao2