Spring注解驱动开发(三)

注解可以简化配置,提高效率

The Spring Framework provides a comprehensive programming and configuration model for modern Java-based enterprise applications - on any kind of deployment platform.

属性赋值@value赋值

使用@Value赋值

  • 基本数值
  • 可以写SPEL表达式 #{}
  • 可以${}获取配置文件信息(在运行的环境变量中的值)

使用xml时候导入配置文件是

1
<context:property-placeholder location="classpath:person.properties"/>

使用注解可以在配置类添加一个@PropertySource注解把配置文件中k/v保存到运行的环境中

使用${key}来获取

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
* @Author: cuzz
* @Date: 2018/9/24 18:43
* @Description:
*/
@PropertySource(value = {"classpath:/person.properties"})
@Configuration
public class MainConfigOfPropertyValue {

@Bean
public Person person() {
return new Person();
}
}

Person 类

1
2
3
4
5
6
7
8
9
10
11
12
@Data
public class Person {

@Value("vhuj")
private String name;

@Value("#{20-2}")
private Integer age;

@Value("${person.nickName}")
private String nickName;
}

测试

1
2
3
4
5
6
7
8
9
10
11
@Test
public void test01() {
printBean(applicationContext);
System.out.println("---------------------------");

Person person = (Person) applicationContext.getBean("person");
System.out.println(person);

System.out.println("---------------------------");

}

输出

1
2
3
---------------------------
Person(name=vhuj, age=18, nickName=三三)
---------------------------

自动装配@Autowired@Qualifier@Primary

自动转配:

Spring利用依赖注入(DI),完成对IOC容器中各个组件的依赖关系赋值

@Autowired自动注入:

  • a. 默认优先按照类型去容器中寻找对应的组件,如果找到去赋值

  • b. 如果找到到相同类型的组件,再将属性名(BookDao bookdao)作为组件的id去容器中查找

  • c. 接下来还可以使用@Qualifier("bookdao")明确指定需要装配的id

  • d. 默认是必须的,我们可以指定 @Autowired(required=false),指定非必须

@Primary让Spring自动装配时首先装配

自动装配@Resource和@Inject

Spring还支持使用@Resource (JSR250) 和@Inject (JSR330) 注解,这两个是java规范

@Resource和@Autowired一样实现自动装配功能,默认是按组件名称进行装配的

没有支持@Primary和@Autowird(required=false)的功能

自动装配其他地方的自动装配

@Autowired:构造器、参数、方法属性等

标注到方法位子上@Bean+方法参数,参数从容器中获取

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/**
* @Author: cuzz
* @Date: 2018/9/24 20:57
* @Description:
*/
public class Boss {
// 属性
@Autowired
private Car car;

// 构造器 如果构造器只有一个有参构造器可以省略
@Autowired
public Boss(@Autowired Car car) {
}

public Car getCar() {
return car;
}

// set方法
@Autowired // 参数
public void setCar(@Autowired Car car) {
this.car = car;
}
}

自动装配Aware注入Spring底层注解

自定义组件想要使用Spring容器底层的一些组件(ApplicationContext,BeanFactory 等等),自定义组件实现xxxAware,在创建对象的时候会调用接口规定的方法注入相关的组件

1
2
3
4
5
6
7
8
9
10
11
/**
* Marker superinterface indicating that a bean is eligible to be
* notified by the Spring container of a particular framework object
* through a callback-style method. Actual method signature is
* determined by individual subinterfaces, but should typically
* consist of just one void-returning method that accepts a single
* argument.
*/
public interface Aware {

}

我们实现几个常见的Aware接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/**
* @Author: cuzz
* @Date: 2018/9/25 10:18
* @Description:
*/
@Component
public class Red implements BeanNameAware ,BeanFactoryAware, ApplicationContextAware {
private ApplicationContext applicationContext;

@Override
public void setBeanName(String name) {
System.out.println("当前Bean的名字: " + name);
}

@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
System.out.println("当前的BeanFactory: " + beanFactory);
}

@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
System.out.println("传入的ioc: " + applicationContext);
}
}

注入到配置中测试

1
2
3
4
5
6
7
8
9
10
11
12
13
/**
* @Author: cuzz
* @Date: 2018/9/25 10:28
* @Description:
*/
public class IOCTestAware {

@Test
public void test01() {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfAware.class);

}
}

测试结果

1
2
3
当前Bean的名字: red
当前的BeanFactory: org.springframework.beans.factory.support.DefaultListableBeanFactory@159c4b8: defining beans [org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.event.internalEventListenerProcessor,org.springframework.context.event.internalEventListenerFactory,mainConfigOfAware,red]; root of factory hierarchy
传入的ioc: org.springframework.context.annotation.AnnotationConfigApplicationContext@1e89d68: startup date [Tue Sep 25 10:29:17 CST 2018]; root of context hierarchy

把Spring自定义组件注入到容器中

原理:

1
public interface ApplicationContextAware extends Aware {}

通过 Debug 方式,定位到 org.springframework.context.support.ApplicationContextAwareProcessor#postProcessBeforeInitialization

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@Override
public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {
AccessControlContext acc = null;

if (System.getSecurityManager() != null &&
(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)) {
acc = this.applicationContext.getBeanFactory().getAccessControlContext();
}

if (acc != null) {
AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
invokeAwareInterfaces(bean);
return null;
}
}, acc);
}
else {
invokeAwareInterfaces(bean); // 调用
}

调用下面方法进行判断,每种 xxxAware 接口中只有一种方法,并调用相应的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
private void invokeAwareInterfaces(Object bean) {
if (bean instanceof Aware) {
if (bean instanceof EnvironmentAware) {
((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
}
if (bean instanceof EmbeddedValueResolverAware) {
((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
}
if (bean instanceof ResourceLoaderAware) {
((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
}
if (bean instanceof ApplicationEventPublisherAware) {
((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
}
if (bean instanceof MessageSourceAware) {
((MessageSourceAware) bean).setMessageSource(this.applicationContext);
}
if (bean instanceof ApplicationContextAware) {
((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
}
}
}

xxxAware都是通过xxxProcessor来处理的

比如:ApplicationContextAware 对应 ApplicationContextAwareProcessor

自动装配@Profile环境搭建

Profile是Spring为我们提供可以根据当前环境,动态的激活和切换一系组件的功能

a. 使用命令动态参数激活:虚拟机参数位子加载 -Dspring.profiles.active=test

b. 使用代码激活环境

我们想配置类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/**
* @Author: cuzz
* @Date: 2018/9/25 10:47
* @Description:
*/
@Configuration
public class MainConfigOfProfile {

@Profile(value = "test")
@Bean(value = "testDataSource")
public DataSource testDataSource() {

System.out.println("testDataSource");
return null;
}

@Profile(value = "dev")
@Bean(value = "devDataSource")
public DataSource devDataSource() {
System.out.println("devDataSource");
return null;
}
}

测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
* @Author: cuzz
* @Date: 2018/9/25 10:59
* @Description:
*/
public class IOCTestProfile {

@Test
public void test01() {
// 1. 使用无参构造器创建一个applicationContext
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
// 2. 设置要激活的环境
applicationContext.getEnvironment().setActiveProfiles("test");
// 3. 注册主配置类
applicationContext.register(MainConfigOfProfile.class);
// 4. 启动刷新容器
applicationContext.refresh();
}
}

输出

1
testDataSource
-------------本文结束感谢您的阅读-------------

本文标题:Spring注解驱动开发(三)

文章作者:cuzz

发布时间:2018年09月25日 - 22:09

最后更新:2019年07月16日 - 19:07

原始链接:http://blog.cuzz.site/2018/09/25/Spring注解驱动开发(三)/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

请博主吃包辣条
0%