一、Autowired
创建 BookController、BookService、BookDao,并通过 @Autowired 注解将 BookService 注入到 BookController 中,将 BookDao 注入到 BookService 中
BookDao:
package org.example.dao;
import org.springframework.stereotype.Repository;
@Repository
public class BookDao {
}
BookService:
package org.example.service;
import org.example.dao.BookDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class BookService {
@Autowired
private BookDao bookDao;
@Override
public String toString() {
return "BookService{" +
"bookDao=" + bookDao +
'}';
}
}
BookController:
package org.example.controller;
import org.example.service.BookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
@Controller
public class BookController {
@Autowired
private BookService bookService;
}
配置类,通过 @ComponentScan 注解将上述三个类扫描到容器中:
package org.example.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@ComponentScan({"org.example.controller","org.example.service","org.example.dao"})
@Configuration
public class MainConfigOfAutowired {
}
测试方法,验证通过自动注入的方式以及直接从容器中获取这两种方式得到的 BookDao 是否是同一个:
@Test
public void testAutowired(){
ApplicationContext ac = new AnnotationConfigApplicationContext(MainConfigOfAutowired.class);
BookService bookService = ac.getBean(BookService.class);
System.out.println(bookService);
BookDao bookDao = ac.getBean(BookDao.class);
System.out.println(bookDao);
}
测试结果:
结果证明,两种获取方式得到的 BookDao 为同一个。
@Autowired默认是根据类型进行注入的,因此如果有多个类型一样的Bean候选者,则需要限定其中一个候选者,否则将抛出异常
二、@Qualifier 注解
创建 PersonDao
package org.example.dao;
public interface PersonDao {
}
创建 PersonDao 的两个实现类 PersonDaoImpl01 和 PersonDaoImpl02
PersonDaoImpl01
package org.example.dao.impl;
import org.example.dao.PersonDao;
import org.springframework.stereotype.Repository;
@Repository("personDao01")
public class PersonDaoImpl01 implements PersonDao {
}
PersonDaoImpl02
package org.example.dao.impl;
import org.example.dao.PersonDao;
import org.springframework.stereotype.Repository;
@Repository("personDao02")
public class PersonDaoImpl02 implements PersonDao {
}
PersonService
package org.example.service;
import org.example.dao.PersonDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
@Service
public class PersonService {
@Qualifier("personDao02")
@Autowired
private PersonDao personDao;
public void print(){
System.out.println(personDao);
}
}
PersonDao 接口有多个实现类,而在 PersonService 中注入 PersonDao 时,Spring 会不确定注入哪一个实现类。而 @Qualifier 可以解决这个问题。
测试方法:
@Test
public void testAutowiredPerson(){
ApplicationContext ac = new AnnotationConfigApplicationContext(MainConfigOfAutowired.class);
PersonService personService = ac.getBean(PersonService.class);
personService.print();
}
测试结果:
取出的是 PersonDaoImpl02 实现类
三、@Primary 注解
@Primary注解可以让 Spring 进行自动装配的时候,默认使用首选的 bean
在 PersonDaoImpl01 上使用 @Primary 注解:
package org.example.dao.impl;
import org.example.dao.PersonDao;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Repository;
@Primary
@Repository("personDao01")
public class PersonDaoImpl01 implements PersonDao {
}
PersonDaoImpl02 保持不变
PersonService 去掉 @Qualifier 注解
package org.example.service;
import org.example.dao.PersonDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
@Service
public class PersonService {
@Autowired
private PersonDao personDao;
public void print(){
System.out.println(personDao);
}
}
测试代码不变,测试结果如下:
四、@Resource 注解
@Resource:可以根据类型注入,也可以根据名称注入
PersonService 使用 @Resource 注解进行注入
package org.example.service;
import org.example.dao.PersonDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
@Service
public class PersonService {
@Resource(name = "personDao02")
private PersonDao personDao;
public void print(){
System.out.println(personDao);
}
}
测试代码不变,测试结果:
五、Aware 接口注入 Spring 底层组件
自定义组件实现 XXXAware,在创建对象的时候,会调用接口规定的方法注入相关组件。Aware 会把 Spring 底层一些组件注入到自定义的 bean 中。
package org.example.pojo;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.EmbeddedValueResolverAware;
import org.springframework.stereotype.Component;
import org.springframework.util.StringValueResolver;
@Component
public class Color implements ApplicationContextAware, BeanNameAware, EmbeddedValueResolverAware {
private ApplicationContext applicationContext;
@Override
public void setBeanName(String name) {
System.out.println("当前 bean 的名称:"+name);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
System.out.println("传入的 IoC 容器" + applicationContext);
this.applicationContext = applicationContext;
}
@Override
public void setEmbeddedValueResolver(StringValueResolver resolver) {
String s = resolver.resolveStringValue("你好 ${os.name},我是 #{20*18}");
System.out.println("解析的字符串:" + s);
}
}
配置文件:
package org.example.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@ComponentScan({"org.example.controller","org.example.service","org.example.dao","org.example.pojo"})
@Configuration
public class MainConfigOfAutowired {
}
测试代码:
@Test
public void testAware(){
ApplicationContext ac = new AnnotationConfigApplicationContext(MainConfigOfAutowired.class);
String[] beanDefinitionNames = ac.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
System.out.println(beanDefinitionName);
}
}
测试结果:
六、@Profile 注解
@Profile 注解可以指定组件在哪个环境的情况下才能被注册到容器中,如果未指定,则任何环境下都可以注册
- 添加了 @Profile 注解的 bean,只有在该环境被激活的时候才能注册到容器中,默认是 default 环境
- 当 @Profile 注解标注在配置类上时,只有是指定的环境的时候,整个配置类里面的所有配置才能开始生效。
pom 文件
创建 dbconfig.properties
db.user=root
db.password=root
db.driverClass=com.mysql.cj.jdbc.Driver
创建 MaiinTestOfProfile 配置类
package org.example.config;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.example.pojo.Yellow;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.EmbeddedValueResolverAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.context.annotation.PropertySource;
import org.springframework.util.StringValueResolver;
import javax.sql.DataSource;
import java.beans.PropertyVetoException;
@Configuration
@PropertySource("classpath:/dbconfig.properties")
public class MainConfigOfProfile implements EmbeddedValueResolverAware {
@Value("${db.user}")
private String user;
private String driverClass;
@Bean
public Yellow yellow(){
return new Yellow();
}
@Profile("testDataSource")
@Bean
public DataSource dataSourceTest(@Value("${db.password}") String password){
ComboPooledDataSource dataSource = new ComboPooledDataSource();
try {
dataSource.setUser(user);
dataSource.setPassword(password);
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test?serverTimezone=GMT&useSSL=false&useUnicode=true&characterEncoding=utf8");
dataSource.setDriverClass(driverClass);
} catch (PropertyVetoException e) {
e.printStackTrace();
}
return dataSource;
}
@Profile("devDataSource")
@Bean
public DataSource dataSourceDev(@Value("${db.password}") String password){
ComboPooledDataSource dataSource = new ComboPooledDataSource();
try {
dataSource.setUser(user);
dataSource.setPassword(password);
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/sys?serverTimezone=GMT&useSSL=false&useUnicode=true&characterEncoding=utf8");
dataSource.setDriverClass(driverClass);
} catch (PropertyVetoException e) {
e.printStackTrace();
}
return dataSource;
}
@Profile("prodDataSource")
@Bean
public DataSource dataSourceProd(@Value("${db.password}") String password){
ComboPooledDataSource dataSource = new ComboPooledDataSource();
try {
dataSource.setUser(user);
dataSource.setPassword(password);
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/mysql?serverTimezone=GMT&useSSL=false&useUnicode=true&characterEncoding=utf8");
dataSource.setDriverClass(driverClass);
} catch (PropertyVetoException e) {
e.printStackTrace();
}
return dataSource;
}
@Override
public void setEmbeddedValueResolver(StringValueResolver resolver) {
String driverClass = resolver.resolveStringValue("${db.driverClass}");
this.driverClass = driverClass;
}
}
测试方法
@Test
public void testProfile01(){
// 创建 ApplicationContext
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext();
// 设置需要激活的环境
ac.getEnvironment().setActiveProfiles("testDataSource", "devDataSource");
// 注册主配置类
ac.register(MainConfigOfProfile.class);
// 刷新容器
ac.refresh();
String[] beanDefinitionNames = ac.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
System.out.println(beanDefinitionName);
}
}
测试结果: