Spring需要使用的组件配置pom.xml
1.@Value赋值
- 使用基本字符串进行赋值
- 使用SpringEL进行赋值
- 使用@PropertySource读取配置文件进行赋值
Bird.java三种对属性进行赋值的方法
public class Bird {
//使用@Value进行赋值:1,基本字符 2,springEL表达式, 3,可以读取 我们的配置文件
@Value("James")
private String name;
@Value("#{20-2}")
private Integer age;
@Value("${bird.color}")
private String color;
配置文件Ch8MainConfig.java
@Configuration
@PropertySource(value="classpath:/test.properties")
public class Ch8MainConfig {
@Bean
public Bird bird(){
return new Bird();
}
}
属性文件test.properties
bird.color=red
测试文件Ch8Test.java
test.properties里面的属性值是会加载到环境变量中的,所以从ConfigurableEnvironment能获取到该属性值。
public class Ch8Test {
@Test
public void test01() {
AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(Ch8MainConfig.class);
//从容器中获取所有bean
String[] names = app.getBeanDefinitionNames();
for (String name : names) {
System.out.println(name);
}
Bird bird = (Bird) app.getBean("bird");
System.out.println(bird);
System.out.println("IOC容器创建完成........");
ConfigurableEnvironment environment = app.getEnvironment();
System.out.println("environment====" + environment.getProperty("bird.color"));
app.close();
}
}
2.自动装配
- @Autowired属于spring的, 不能脱离spring
- @Resource和@Inject都是JAVA规范
@Inject是需要引入第三方包 - 推荐大家使用@Autowired
@Inject与@Autowired的区别如下: - @Inject和Autowired一样可以装配bean, 并支持@Primary功能, 可用于非spring框架.
- @Inject缺点: 但不能支持@Autowired(required = false)的功能,需要引入第三方包javax.inject
@Resource和Autowired的区别如下: - @Resource和Autowired一样可以装配bean
- @Resource缺点:
不能支持@Primary功能
不能支持@Autowired(required = false)的功能
2.1 @Autowired行为
1)比较TestService拿到testDao与直接从容器中拿到的testDao是否为同一个?
- 三个业务类
TestController.java
TestService.java
TestDao.java
@Controller
public class TestController {
@Autowired
private TestService testService;
}
@Service
public class TestService {
@Autowired
private TestDao testDao;//如果使用Autowired, testDao2, 找到TestDao类型的
public void println(){
System.out.println(testDao);
}
}
@Repository
public class TestDao {
}
- 配置类
Ch9MainConfig.java
@Configuration
@ComponentScan({"com.wangzhen.ch9.controller","com.wangzhen.ch9.service","com.wangzhen.ch9.dao"})
public class Ch9MainConfig {
}
- 测试类
Ch9Test.java
public class Ch9Test {
@Test
public void test01(){
AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(Ch9MainConfig.class);
System.out.println(app);
TestService testService = app.getBean(TestService.class);
testService.println();
//直接从容器中获取TestDao, 和使用Autowired注解来取比较
TestDao testDao = app.getBean(TestDao.class);
System.out.println(testDao);
app.close();
}
}
测试结果:
com.wangzhen.ch9.dao.TestDao@7ef27d7f
com.wangzhen.ch9.dao.TestDao@7ef27d7f
结果表明:是同一个testDao。
@Autowired默认优先按类型去容器中找对应的组件,相当于app.getBean(TestDao.class)去容器获取id为testDao的bean, 并注入到TestService的bean中;
使用方式如下:
TestService{
@Autowired
private TestDao testDao;//默认去容器中找id为”testDao”的bean
}
2)@Autowired其他加载方式(除了域加载)
- 方法加载
Sun.java
@Component
public class Sun {
private Moon moon;
public Sun(Moon moon){
this.moon = moon;
System.out.println("..Constructor................");
}
public Moon getMoon() {
return moon;
}
@Autowired
public void setMoon(Moon moon) {
this.moon = moon;
}
@Override
public String toString() {
return "Sun [moon=" + moon + "]";
}
}
测试Ch9Test.java
Moon moon = (Moon)app.getBean(Moon.class);
System.out.println(moon);
Sun sun = (Sun)app.getBean(Sun.class);
System.out.println(sun.getMoon());
结果如下:
com.wangzhen.ch9.bean.Moon@4b41dd5c
com.wangzhen.ch9.bean.Moon@4b41dd5c
- 方法内部的使用参数加载
public Sun(@Autowired Moon moon){
this.moon = moon;
System.out.println("..Constructor................");
}
- 构造方法加载
@Autowired
public Sun(Moon moon){
this.moon = moon;
System.out.println("..Constructor................");
}
2.2 定义多个同类对象,加载哪个类对象
- 业务类做点打印修改
@Service
public class TestService {
@Autowired
private TestDao testDao;//如果使用Autowired, testDao2, 找到TestDao类型的
public void println(){
System.out.println("Service...dao...."+testDao);
}
}
@Repository
public class TestDao {
private String flag = "1";
public String getFlag() {
return flag;
}
public void setFlag(String flag) {
this.flag = flag;
}
@Override
public String toString() {
return "TestDao...... [flag=" + flag + "]";
}
}
- 在配置类中增加一个testDao的注入
@Configuration
@ComponentScan({"com.wangzhen.ch9.controller","com.wangzhen.ch9.service","com.wangzhen.ch9.dao"})
public class Ch9MainConfig {
//spring进行自装配的时候默认首选的bean
@Bean("testDao")
public TestDao testDao(){
TestDao testDao = new TestDao();
testDao.setFlag("2");
return testDao;
}
}
结果是:
Service...dao....TestDao...... [flag=2]
TestDao...... [flag=2]
- 如果将TestService中的testDao改为testDao2
@Service
public class TestService {
@Autowired
private TestDao testDao2;//如果使用Autowired, testDao2, 找到TestDao类型的
public void println(){
System.out.println("Service...dao...."+testDao2);
}
}
结果依然不变,还是:
Service...dao....TestDao...... [flag=2]
TestDao...... [flag=2]
2.3 使用@Qualifier,加载哪个类对象
- TestService声明@Qualifier("testDao")
@Service
public class TestService {
@Qualifier("testDao")//指定名称来加载
@Autowired
private TestDao testDao2;//如果使用Autowired, testDao2, 找到TestDao类型的
public void println(){
System.out.println("Service...dao...."+testDao2);
}
}
- 配置文件将注入的Bean改名
@Configuration
@ComponentScan({"com.wangzhen.ch9.controller","com.wangzhen.ch9.service","com.wangzhen.ch9.dao","com.wangzhen.ch9.bean"})
public class Ch9MainConfig {
//spring进行自装配的时候默认首选的bean
//@Primary //只要在这里申请Primary, 代表所有要注入TestDao的bean,
@Bean("testDao2")
public TestDao testDao(){
TestDao testDao = new TestDao();
testDao.setFlag("2");
return testDao;
}
}
结果:
Service...dao....TestDao...... [flag=1]
org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.wangzhen.ch9.dao.TestDao' available: expected single matching bean but found 2: testDao,testDao2
如果为以下情况,则报错:
Qualifier为testDao2,而@Bean为testDao
@Service
public class TestService {
@Qualifier("testDao2")//指定名称来加载
@Autowired
private TestDao testDao;//如果使用Autowired, testDao2, 找到TestDao类型的
public void println(){
System.out.println("Service...dao...."+testDao);
}
}
@Configuration
@ComponentScan({"com.wangzhen.ch9.controller","com.wangzhen.ch9.service","com.wangzhen.ch9.dao","com.wangzhen.ch9.bean"})
public class Ch9MainConfig {
//spring进行自装配的时候默认首选的bean
@Primary //只要在这里申请Primary, 代表所有要注入TestDao的bean,
@Bean("testDao")
public TestDao testDao(){
TestDao testDao = new TestDao();
testDao.setFlag("2");
return testDao;
}
}
2.4 @Autowired的required属性
- 注释掉@Repository和@Bean("testDao2"),即容器中没有任何一个testDao
@Service
public class TestService {
@Qualifier("testDao")//指定名称来加载
@Autowired(required=false)
private TestDao testDao2;//如果使用Autowired, testDao2, 找到TestDao类型的
public void println(){
System.out.println("Service...dao...."+testDao2);
}
}
结果:不会报错
Service...dao....null
2.5 @Primary
- TestService的修改
@Service
public class TestService {
//@Qualifier("testDao")//指定名称来加载
@Autowired
private TestDao testDao;//如果使用Autowired, testDao2, 找到TestDao类型的
public void println(){
System.out.println("Service...dao...."+testDao);
}
}
- 配置文件加入Primary
@Configuration
@ComponentScan({"com.wangzhen.ch9.controller","com.wangzhen.ch9.service","com.wangzhen.ch9.dao","com.wangzhen.ch9.bean"})
public class Ch9MainConfig {
//spring进行自装配的时候默认首选的bean
@Primary //只要在这里申请Primary, 代表所有要注入TestDao的bean,
@Bean("testDao2")
public TestDao testDao(){
TestDao testDao = new TestDao();
testDao.setFlag("2");
return testDao;
}
}
结果:
Service...dao....TestDao...... [flag=2]
TestDao...... [flag=2]
2.6 同时存在@Qualifier和@Primary加载顺序
- TestService的修改
@Service
public class TestService {
@Qualifier("testDao")//指定名称来加载
@Autowired
private TestDao testDao;//如果使用Autowired, testDao2, 找到TestDao类型的
public void println(){
System.out.println("Service...dao...."+testDao);
}
}
- 配置文件
@Configuration
@ComponentScan({"com.wangzhen.ch9.controller","com.wangzhen.ch9.service","com.wangzhen.ch9.dao","com.wangzhen.ch9.bean"})
public class Ch9MainConfig {
//spring进行自装配的时候默认首选的bean
@Primary //只要在这里申请Primary, 代表所有要注入TestDao的bean,
@Bean("testDao2")
public TestDao testDao(){
TestDao testDao = new TestDao();
testDao.setFlag("2");
return testDao;
}
}
结果:
Service...dao....TestDao...... [flag=1]
TestDao...... [flag=2]
此时不会报错,第二个getBean取得是Primary指定的,而Qualifier取得是另外一个指定名字的。两个同时存在。
2.7 @Resource
- TestService的修改
@Service
public class TestService {
//@Qualifier("testDao")//指定名称来加载
//@Autowired
@Resource
private TestDao testDao;//如果使用Autowired, testDao2, 找到TestDao类型的
public void println(){
System.out.println("Service...dao...."+testDao);
}
}
结果:
Service...dao....TestDao...... [flag=1]
TestDao...... [flag=2]
小结:@Resource和Autowired的区别如下:
- @Resource和Autowired一样可以装配bean
- @Resource缺点:
不能支持@Primary功能
不能支持@Autowired(required = false)的功能
2.8 @Inject
一模一样的用法!
@Inject与@Autowired的区别如下:
- @Inject和Autowired一样可以装配bean, 并支持@Primary功能, 可用于非spring框架.
- @Inject缺点: 但不能支持@Autowired(required = false)的功能,需要引入第三方包javax.inject
3.Aware注入Spring底层组件原理
参考Bean生命周期——4.2 ApplicationContextAwareProcessor实现分析
自定义组件想要使用Spring容器底层的组件(ApplicationContext, BeanFactory, ......)
思路: 自定义组件实现xxxAware, 在创建对象的时候, 会调用接口规定的方法注入到相关组件:Aware
查看有哪些接口继承了Aware接口:
实现ApplicationContextAware、BeanNameAware和EmbeddedValueResolverAware接口:
ApplicationContextAware接口: 获取IOC容器
BeanNameAware接口: 获取Bean信息
EmbeddedValueResolverAware接口: 解析器(表达式及相关脚本解析)
ApplicationContextAware接口获取IOC容器
AnnotationConfigApplicationContext加载配置文件获取的容器
参考Light.java
@Component
public class Light 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 result = resolver.resolveStringValue("你好${os.name}, 计算#{3*8}");
System.out.println("解析的字符串为---"+result);
}
}
结果:
当前bean的名字:light
解析的字符串为---你好Windows 7, 计算24
传入的IOC容器: org.springframework.context.annotation.AnnotationConfigApplicationContext@7f77e91b: startup date [Mon Sep 10 16:11:54 CST 2018]; root of context hierarchy
总结:把Spring底层的组件可以注入到自定义的bean中,ApplicationContextAware是利用ApplicationContextAwareProcessor来处理的,其它XXXAware也类似, 都有相关的Processor来处理,其实就是后置处理器来处理。
XXXAware---->功能使用了XXXProcessor来处理的,这就是后置处理器的作用;
ApplicaitonContextAware--->ApplicationContextProcessor后置处理器来处理的
参考
- 1)享学课堂James老师笔记