@Autowired
注解BookService类使用@Autowired
注解自动装配BookDao
属性
@Service
public class BookService {
@Autowired
private BookDao bookDao;
public void print(){
System.out.println(bookDao);
}
}
配置类
/**
* 自定装配
*
* spring利用依赖注入(DI),完成对IOC容器中各个组件的依赖关系赋值
*/
@ComponentScan({"spring.annotation.service","spring.annotation.dao","spring.annotation.controller"})
@Configuration
public class MainConfigAutowired {
}
测试
@Test
public void testAutowired(){
ApplicationContext context = new AnnotationConfigApplicationContext(MainConfigAutowired.class);
BookService bookService = context.getBean(BookService.class);
bookService.print();
BookDao bookDao = context.getBean(BookDao.class);
System.out.println(bookDao);
}
输出结果:
通过打印的booDao
对象可以看出,bookService
对象里面注入的bookDao
属性和IOC容器中的是同一个对象。
@Autowired
注解实现自动注入,默认优先按照类型去容器中找对应的组件,如果找到多个相同类型的组件,再将属性的名称作为组件的id
去容器中查找。
可以使用@Qualifier
注解明确指定需要装配的组件id
,而不是使用属性名称去查找。
自动装配默认必须赋值,如果在容器中没有找到对应的组件就会报错,可以使用@Autowired(required = false)
在没有装配成功的情况下不会报错,而是赋值为null
。
@Primary
注解可以指定首选组件,即有多个相同类型组件时,默认装配标有@Primary
注解的组件。也可以同时使用@Qualifier
注解强制装配指定的组件。
@Resource
和@Inject
@Resource
和@Inject
是****,也能完成自动注入
@Resource
注解默认是按照组件名称进行装配的,不支持和@Primary
和@Autowired
注解配合使用
@Resource
private BookDao bookDao;
@Inject
注解也是可以自动装配,需要单独导入依赖
@Inject
private BookDao bookDao;
所有的自动装配注解都是由AutowiredAnnotationBeanPostProcessor
这个后置处理器来解析完成自动装配功能。
@Autowired
注解可以标注在方法上@Controller
public class BookController {
private BookService bookService;
//@Autowired注解标注在方法上,spring容器创建当前对象就会调用方法完成赋值
//方法使用的参数,自定义类型的值从ioc容器中获取
@Autowired
public void setBookService(BookService bookService) {
this.bookService = bookService;
}
@Override
public String toString() {
return "BookController{" +
"bookService=" + bookService +
'}';
}
}
测试
@Test
public void testAutowiredMethod(){
ApplicationContext context = new AnnotationConfigApplicationContext(MainConfigAutowired.class);
BookController bookController = context.getBean(BookController.class);
System.out.println(bookController);
BookService bookService = context.getBean(BookService.class);
System.out.println(bookService);
}
输出结果:
通过打印日志可以看出,BookController
中通过set
方法自动装配的BookService
组件,和IOC容器的BookService
组件是同一个。
@Bean
标注的方法创建对象的时候,方法参数的值从容器中获取
@ComponentScan({"spring.annotation.service","spring.annotation.dao","spring.annotation.controller"})
@Configuration
public class MainConfigAutowired {
@Bean
public Boy boy(BookService bookService){
Boy boy = new Boy();
boy.setBookService(bookService);
return boy;
}
}
测试
@Test
public void testAutowiredMethod(){
ApplicationContext context = new AnnotationConfigApplicationContext(MainConfigAutowired.class);
BookService bookService = context.getBean(BookService.class);
System.out.println(bookService);
Boy boy = context.getBean(Boy.class);
System.out.println(boy.getBookService());
}
@Autowired
注解可以标注在构造器上默认加在ioc容器中的组件,容器启动会调用无参构造器创建对象,再进行初始化赋值等操作。可以把@Autowired
注解标注在构造器上来自动装配组件。如果组件只有一个有参构造器,这个有参构造器@Autowired
注解可以省略。
@Autowired
public BookController(BookService bookService) {
System.out.println("调用BookController有参构造器...");
this.bookService = bookService;
}
@Autowired
注解可以标注在参数上 public BookController(@Autowired BookService bookService) {
System.out.println("调用BookController有参构造器...");
this.bookService = bookService;
}
public void setBookService(@Autowired BookService bookService) {
this.bookService = bookService;
}
自定义组件想要使用Spring容器底层的一些组件,如ApplicationContext
、BeanFactory
等等,需要自定义组件实现对应的Aware
接口,在创建对象的时候,就会调用接口规定的方法注入相关组件。每个Aware
都有与之对应的BeanProcessor
后置处理器,通过后置处理器来处理实现了对应接口的Bean。
创建Guy
组件,Guy
用到的其它组件功能都会以接口方法回调的方式传入相关的组件,进而调用组件相应的方法
@Component
public class Guy implements ApplicationContextAware, BeanNameAware, EmbeddedValueResolverAware {
private ApplicationContext applicationContext;
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
System.out.println("传入的IOC容器:" + applicationContext);
}
public void setBeanName(String name) {
System.out.println("当前Bean的名字:" + name);
}
public void setEmbeddedValueResolver(StringValueResolver resolver) {
//解析字符串占位符
String resolveStringValue = resolver.resolveStringValue("本机OS:${os.name}");
System.out.println("解析的字符串:" + resolveStringValue);
}
}
Guy
组件初始化的时候利用后置处理器判断Guy
实现了ApplicationContextAware
接口,然后后置处理器调用setApplicationContext
方法将ioc容器传了过来
@Profile
根据环境注册BeanProfile
是spring提供可以根据当前环境,动态的激活和切换一系列组件的功能
配置类
@PropertySource("classpath:/dbconfig.properties")
@Configuration
public class MainConfigOfProfile implements EmbeddedValueResolverAware{
@Value("${db.user}")
private String user;
private StringValueResolver valueResolver;
private String driverClass;
@Bean("testDataSource")
public DataSource dataSourceTest(@Value("${db.password}") String pwd) throws Exception {
ComboPooledDataSource dataSource= new ComboPooledDataSource();
dataSource.setUser(user);
dataSource.setPassword(pwd);
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test");
driverClass = valueResolver.resolveStringValue("${db.driverClass}");
dataSource.setDriverClass(driverClass);
return dataSource;
}
@Bean("devDataSource")
public DataSource dataSourceDev(@Value("${db.password}") String pwd) throws Exception {
ComboPooledDataSource dataSource= new ComboPooledDataSource();
dataSource.setUser(user);
dataSource.setPassword(pwd);
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/myemployees");
driverClass = valueResolver.resolveStringValue("${db.driverClass}");
dataSource.setDriverClass(driverClass);
return dataSource;
}
@Bean("prodDataSource")
public DataSource dataSourceProd(@Value("${db.password}") String pwd) throws Exception {
ComboPooledDataSource dataSource= new ComboPooledDataSource();
dataSource.setUser(user);
dataSource.setPassword(pwd);
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/mybatis");
driverClass = valueResolver.resolveStringValue("${db.driverClass}");
dataSource.setDriverClass(driverClass);
return dataSource;
}
public void setEmbeddedValueResolver(StringValueResolver resolver) {
this.valueResolver = resolver;
}
}
在没有使用@Profile
注解时,IOC容器启动时所有的bean都会注册到容器中
使用@Profile
指定组件在哪个环境的情况下才能被注册到容器中
@PropertySource("classpath:/dbconfig.properties")
@Configuration
public class MainConfigOfProfile implements EmbeddedValueResolverAware{
@Value("${db.user}")
private String user;
private StringValueResolver valueResolver;
private String driverClass;
@Profile("test")
@Bean("testDataSource")
public DataSource dataSourceTest(@Value("${db.password}") String pwd) throws Exception {
ComboPooledDataSource dataSource= new ComboPooledDataSource();
dataSource.setUser(user);
dataSource.setPassword(pwd);
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test");
driverClass = valueResolver.resolveStringValue("${db.driverClass}");
dataSource.setDriverClass(driverClass);
return dataSource;
}
@Profile("dev")
@Bean("devDataSource")
public DataSource dataSourceDev(@Value("${db.password}") String pwd) throws Exception {
ComboPooledDataSource dataSource= new ComboPooledDataSource();
dataSource.setUser(user);
dataSource.setPassword(pwd);
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/myemployees");
driverClass = valueResolver.resolveStringValue("${db.driverClass}");
dataSource.setDriverClass(driverClass);
return dataSource;
}
@Profile("prod")
@Bean("prodDataSource")
public DataSource dataSourceProd(@Value("${db.password}") String pwd) throws Exception {
ComboPooledDataSource dataSource= new ComboPooledDataSource();
dataSource.setUser(user);
dataSource.setPassword(pwd);
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/mybatis");
driverClass = valueResolver.resolveStringValue("${db.driverClass}");
dataSource.setDriverClass(driverClass);
return dataSource;
}
public void setEmbeddedValueResolver(StringValueResolver resolver) {
this.valueResolver = resolver;
}
}
使用命令行动态参数,在虚拟机参数位置设置运行时环境为test
输出结果:
还可以使用代码方式激活某种环境
@Test
public void testProfile(){
//创建AnnotationConfigApplicationContext
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
//设置需要激活的环境
context.getEnvironment().setActiveProfiles("test","dev");
//注册主配置类
context.register(MainConfigOfProfile.class);
//启动刷新容器
context.refresh();
String[] beanNamesForType = context.getBeanNamesForType(DataSource.class);
for (String beanName : beanNamesForType){
System.out.println(beanName);
}
}