Spring Annotation Notes

Spring 注解驱动开发#

容器(Container)#

配置类 == 配置文件

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
26
27
28
29
30
31
32
33
//配置类
@Configuration //告诉spring这事一个配置类
//@ComponentScan //value表示要扫描包的位置
//excludeFilters 要排除哪些Component,里面装着是Filter[]
@ComponentScan(value="com.atguigu", excludeFilters = {
@Filter(type="FilterType.ANNOTATION",classes={Controller.class})
})
//Filter的type是表明按照什么方式去排除,里面有5种,分别是:FilterType.ANNOTATION, FilterType.ASPECTJ, FilterType.ASSIGNABLE, FilterType.CUSTOM, FilterType.REGEX 在后面跟classes 表明要去掉哪些包
//FilterType.ANNOTATION 按照注解
//FilterType.ASSIGNABLE_TYPE 按照给定的类型
@Filter(type="FilterType.ASSIGNABLE_TYPE",classes={BookService.class})
//FilterType.ASPECTJ 使用ASPECTJ表达式
//FilterType.REGEX 使用正则表达式规则
//FilterType.CUSTOM 给定一个TypeFilter的实现类
@Filter(type=FilterType.CUSTOM, classes={MyTypeFilter.class}) //就是看MyTypeFilter里面的math返回true或者false来决定匹不匹配

//includeFilters 扫描的时候只需要包含哪些组件,里面装着是Filter[] 注意只包含生效的条件是要禁用默认规则,默认规则是扫描所有的因此要禁用掉
@ComponentScan(value="com.atguigu", includeFilters = {
@Filter(type="FilterType.ANNOTATION",classes={Controller.class})},useDefaultFilters = false)
//制定扫描策略,可以写多条
@ComponentScans(
value = {
@ComponentScan(value="com.atguigu", includeFilters = {
@Filter(type="FilterType.ANNOTATION",classes={Controller.class})},useDefaultFilters = false)
}
)
public class MainConfig{
//给容器中注册一个Bean; 类型为返回值的类型,id默认是方法名作为id
@Bean("person")
public Person person(){
return new Person("lisi",20);
}
}

MyTypeFilter.java 自定义Filter的实现类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class MyTypeFilter implements TypeFilter{
//metadatareader读取的是当前正在扫描的类的信息
//MetaDataReaderFactory 可以获取到其他任何类的信息
@Override
public boolean math(MetadataReader metadataReader, MetaDataReaderFactory metadatareaderfactory) {
//获取当前类注解的信息
AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
//获取当前正在扫描类的类信息
ClassMetadata classMetadata = metadataReader.getClassMetadata();
//获取当前类资源信息(类的路径)
Resource resource = metadataReader.getResource();
//classMetadata 可以获取到当前类名 当前类子类、父类类名
return false;
}
}

使用@Scope调整作用域

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
@Configuration
//类中组件统一设置 满足当前条件,这个类中配置的所有bean注册才能生效
@Conditional({WindowsCondition.class})
@Import({Color.class, Red.class, MyImportSelector.class, MyImportBeanDefinitionRegistrar})
public class MainConfig2{
/*
* 默认是单实例的
* ConfigurableBeanFactory#SCOPE_PROTOTYPE -> "prototype"
* ConfigurableBeanFacotry#SCOPE_SINGLETON -> "singleton"
* org.springframework.web.context.WebApplicationContext#SCOPE_REQUEST -> request
* org.springframework.web.context.WebApplicationContext#SCOPE_SESSION -> session
*
* prototype: 多实例: ioc容器启动并不会去调用方法创建对象放在容器中 每次获取的时候才会调用方法创建对象
* singleton: 单实例(默认值) ioc容器启动会调用方法创建对象放到ioc容器中。以后每次获取就是直接从容器中(map.get())拿。
* request: 同一请求创建一个实例
* session: 同一个session创建一个实例
*
* 懒加载 @Lazy
* 单实例bean:默认在容器启动的时候创建对象
* 懒加载: 容器启动不创建对象。在第一次使用(获取)Bean创建对象,并初始化。
*/
@Scope("prototype"/"singleton")
@Lazy
@Bean("person")
public Person person() {
return new Person("zhangsan",25);
}

/**
* @Conditional({Conditon}): 按照一定的条件进行判断,满足条件给容器中注册bean
* 如果系统是windows,给容器中注册("bill")
* 如果系统是linux,给容器中注册("linux")
*/
@Conditional({WindowsCondition.class})
@Bean("bill")
public Person person01(){
return new Person("Bill Gates",62);
}

@Conditional({LinuxCondition.class})
@Bean("linus")
public Person person02(){
return new Person("linus", 48);
}

/*
* 给容器中注册组件
* 1. 包扫描+标注注解(@Controller/@Service/@Service/@Repository/@Component)[自己写的]
* 2. 使用@Bean[导入的第三方包的组件] --> 每次导入都需要写一条 有些麻烦
* 3. @Import[快速的给容器导入一个组件]
* 1. @Import(要导入的组件) //容器中就会自动注册这个组件,id默认为全类名
* 2. @ImportSelector(返回需要导入的组件的全类名数组)
* 3. @ImportBeanDefinitionRegistrar: 手动注册bean到容器中
* 4. 使用Spring提供的FactoryBean(工厂bean)
* 1. 默认获取到的是工厂bean本身调用getObject创建的对象
* 2. 要获取工厂bean本身,我们需要给id前面加一个&
* &colorFactoryBean
*/

//工厂bean获取的是调用getObject方法创建的对象,直接打印显示的是ColorFactoryBean 但是调用getClass的时候返回的是Color
@Bean
public ColorFactoryBean colorFactoryBean(){
return new ColorFactoryBean();
}

}

Color

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//随便创一个,假装外部组件
public class Color{

}
public class Red{

}
public class Blue{

}
public class Yellow{

}
public class RainBow{

}

MyImportSelector.java

1
2
3
4
5
6
7
8
9
10
11
12
13
//自定义逻辑 返回需要导入的组件
public class MyImportSelector implements ImportSelector{

//返回值就是导入到容器中的组件全类名
//AnnotationMetadata 当前标注@Import注解的类的所有注解信息
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata){

//方法不要返回null
//return null;
return new String[]{"com.bean.Blue", "com.bean.Yellow"};
}
}

LinuxCondition.java

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
26
27
28
29
//判断是否是linux系统
public class LinuxCondition implements Condition {

/*
* ConditionContext: 判断条件能使用的上下文(环境)
* AnnotatedTypeMetadata: 注释信息
*/
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
// 是否是linux系统
//1、能获取到ioc使用的beanfactory
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
//2、获取到类加载器
ClassLoader classLoader = context.getClassLoader();
//3、获取当前环境
Environment environment = context.getEnvironment();
//4、获取到bean定义的注册类
BeanDefinitionRegistry registry = context.getregistry();

//可以判断容器中的bean注册情况,也可以给容器中注册bean
boolean definition = registry.containsBeanDefinition("person");

String property = environment.getProperty("os.name");
if(property.contains("Linux")) {
return true;
}
return false;
}
}

MyImportBeanDefinitionRegistrar.java –> 手工注册

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar{

/*
*
* AnnotationMetadata: 当前类的注解信息
* BeanDefinitionRegistry: BeanDefinition注册类
* 把所有需要添加到容器中的bean, 调用 beanDefinitionRegistry.registerBeanDefinitions 手工注册
*/

@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
boolean definition = registry.containsBeanDefinition("Red->要写全类名");
boolean definition2 = registry.containsBeanDefinition("Blue->要写全类名");
if(definition && definition2) {
//制定bean的定义信息 Bean的类型 Bean的scope
RootBeanDefinition beanDefinition new RootBeanDefinition(Rainbow.class);
//注册一个Bean
registry.registerBeanDefinitions("rainBow",beanDefinition);
}
}
}

ColorFactoryBean

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//创建一个spring定义的FactoryBean
public class ColorFactoryBean implements FactoryBean<Color>{
//返回一个Color对象,这个对象会添加到容器中
@Override
public Color getObject() thorws Exception{
return new Color();
}

@Override
public Class<?> getObjectType() {
return Color.class
}

//是单例?
//true 这个bean是单实例,在容器中会保存一份
//false 这是一个多实例,每次获取都会创建一个新的bean -> 调用getObject方法
@Override
public boolean isSingleton(){
return false;
}
}

WindowsCondition

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//判断是否是windows系统
public class WindowsCondition implements Condition {

/*
* ConditionContext: 判断条件能使用的上下文(环境)
* AnnotatedTypeMetadata: 类的注解信息
*/

@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
Environment environment = context.getEnvironment();
String property = environment.getProperty("os.name");
if(property.contains("Windows")) {
return true;
}
return false;
}
}

配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
<!--配置文件-->

<!-- 包扫描、只要标注了@Controller, @Service, @Repository, @Component -->
<!-- use-default-filters true表示默认允许所有 -->
<context:component-scan base-package="com.atguigu" use-default-filters="false"></context:component-scan>
<context:property-placeholder location="classpath:person.properties"/>
<!-- init-method 和 destroy-method可以指定bean的初始化方法和销毁方法 -->
<bean id="person" class="com.bean.Person" scope="singleton" init-method="" destroy-method="">
<property name="age" value="18"></property>
<property name="name" value="zhangsan"></property>
</bean>
<!-- 开启基于注解版的切面功能 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>

BookController.java

1
2
3
4
5
@Controller
public class BookController{
@AutoWired(required=false) // true:强制要求 false如果找不到就不装配了
private BookService bookService;
}

BookService.java

1
2
3
4
5
@Service
public class BookService{
@AutoWired
private BookDao bookDao;
}

BookDao.java

1
2
3
4
@Repository
public class BookDao{

}

Main 函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class MainTest{
public static void main(String... args) {
//配置文件方式启动
//返回ioc容器
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
Person bean = (Person) applicationContext.getBean("person");
System.out.println(bean);
//配置类方式启动
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
Person bean = applicationContext.getBean("person");
System.out.println(bean);

String[] namesForType = applicationContext.getBeanNamesForType(Person.class);
//person
for(String string : namesForType) {
System.out.println(string);
}
}
}

IOCTest.java

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
public class IOCTest{
@Test
public void test01(){
AnnotationConfigapplicationContext applicationContext new AnnotationConfigapplicationContext(MainConfig.class);
String[] definitionNames applicationContext.getBeanDefinitionName();
for(String name : definitionNames) {
System.out.println(name);
}
/* Output
* mainConfig
* bookController -> 要被排除掉
* bookDao
* bookService -> 要被排除掉
* person
*/
}

public void test02(){
AnnotationConfigapplicationContext applicationContext new AnnotationConfigapplicationContext(MainConfig2.class);
String[] definitionNames applicationContext.getBeanDefinitionName();
for(String name : definitionNames) {
System.out.println(name);
}
//默认是单实例的
//bean == bean2
Object bean = applicationContext.getBean("person");
Object bean2 = applicationContext.getBean("person");
}

public void test03(){
AnnotationConfigapplicationContext applicationContext new AnnotationConfigapplicationContext(MainConfig2.class);
//获取当前context运行环境
ConfigurableEnvironment environment = applicationContext.getEnvironment();
environment.getProperty("os.name");
//动态获取环境变量的值
System.out.println(property);

String[] definitionNames applicationContext.getBeanNamesForType(Person.class);
for(String name : definitionNames) {
System.out.println(name);
}
Map<String, Person> persons = applicationContext.getBeansOfType(Person.class);
System.out.println(persons);
}

@Test
public void testImport(){
AnnotationConfigapplicationContext applicationContext new AnnotationConfigapplicationContext(MainConfig2.class);
String[] definitionNames applicationContext.getBeanDefinitionName();
for(String name : definitionNames) {
System.out.println(name);
}
Blue bean = applicationContext.getBean(Blue.class);
System.out.println(bean);

//工厂bean获取的是调用getObject方法创建的对象
Object bean2 = applicationContext.getBean("colorFactoryBean");
System.out.println("bean的类型" + bean2.getClass());
//Output: color

//通过id获取
Object bean3 = applicationContext.getBean("&colorFactoryBean");
System.out.println("bean的类型" + bean3.getClass());
//class -> ColorFactoryBean
}
}

Bean的生命周期

MainConfigOfLifeCycle.java

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
/* bean的生命周期
* bean的创建---初始化---销毁的过程
* 容器管理bean的生命周期
* 我们可以自定义初始化和销毁方法,容器在bean进行到当前生命周期的时候来调用我们自定义的初始化和销毁方法
*
* 构造(对象创建)
* 单实例,在容器启动的时候创建对象
* 多实例,在容器获取的时候创建对象
* 初始化
* 对象创建完成,并赋值好,调用初始方法。。。
* 销毁
* 单实例bean 容器关闭的时候进行销毁
* 多实例bean 容器不会管理这个bean 容器不会调用销毁方法
*
* 遍历得到容器中所有的BeanPostProcessor 挨个执行beforeInitialization 一旦返回null 就直接跳出for循环 不会执行后面的BeanPostProcessor.applyBeanPostProcessorsBeforeInitialization
*
*
* BeanPostProcessor的原理
* polulateBean(beanName, mbd, instanceWrapper); //给bean进行属性赋值
* => initialization
* {
* applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
* invokeInitMethods(beanName, wrappedBean, mbd); //执行自定义初始化方法
* applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
* }
*
* 1 指定初始化和销毁方法
* init-method 和 destroy-method 以前使用配置文件指定
* 通过@Bean指定init-method和destroy-method
*
* 2 通过让bean实现Initializingbean来定义初始化逻辑 DisposableBean(定义销毁逻辑)
*
* 3 可以使用JRS250
* @PostConstruct 在bean创建完成并且属性赋值完成 来执行初始化
* @PreDestroy 在容器销毁bean之前通知我们进行清理工作
*
* 4 BeanPostProcessor[interface] bean的后置处理器
* 在bean初始化前后做一些处理工作->即使bean没有指定初始化方法
* postProcessBeforeInitialization: 在初始化之前进行后置处理工作
* postProcessAfterInitilization: 在初始化之后进行后置处理工作
*
* Spring底层对BeanPostProcessor的使用 ->底层好多
* bean的赋值 注入其他组件 @Autowired生命周期注解功能 @Async BeanPostProcessor
*
*/
@Configuration
@ComponentScan("com.bean")
public class MainConfigOfLifeCycle{

@bean(initMethod="init",destroyMethod="destroy")
public Car car(){
return new Car();
}
}

MyBeanPostProcessor.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/*
* 自定义后置处理器,初始化前后进行处理工作
* 将后置处理器加入到容器中
*/
@Component
public class MyBeanPostProcessor implements BeanPostProcessor{
@Override
public Object postProcessBeforeInitialization(Object bean,String beanName) throws BeanException{
System.out.println(beanName + "=>" + bean);
return bean;
}
@Override
public Object postProcessAfterInitilization(Object bean,String beanName) throws BeanException{
System.out.println(beanName + "=>" + bean);
return bean;
}
}

Car.java

1
2
3
4
5
6
7
8
9
10
11
public class Car{
public Car(){
System.out.println("car constructor");
}
public init(){
System.out.println("car init...");
}
public destroy(){
System.out.println("car destroy...");
}
}

Cat.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Component
public class Cat implements InitilizingBean, DisposableBean{
public Cat(){
System.out.println("cat instructor");
}

@Override
public void destroy() throws Exception{
System.out.println("cat... destroy...");
}
@Override
public void afterPropertiesSet() throws Exception{
System.out.println("Cat... afterPropertiesSet...");
}
}

Dog.java

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
@Component
public class Dog implements ApplicationContextAware{

private ApplicationContext applicationContext;

public Dog(){
System.out.println("dog constructor");
}

//对象创建并赋值之后调用
@PostConstruct
public void init(){
System.out.println("dog @PostConstruct...");
}
//容器移除对象之前
@PreDestroy
public void destroy(){
System.out.println("dog @PostDestroy");
}

@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeanException{
this.applicationContext = applicationContext;
}
}

IOCTest_LifeCycle.java

1
2
3
4
5
6
7
8
9
10
11
public class IOCTest_LifeCycle{

@Test
public void test01(){
//创建ioc容器
AnnotationConfigapplicationContext applicationContext new AnnotationConfigapplicationContext(MainConfigOfLifeCycle.class);
System.out.println("容器创建完成");

applicationContext.close();
}
}

属性赋值

MainConfigOfPropertyValues.java

1
2
3
4
5
6
7
8
9
@Configuration
//使用@PropertySource读取外部配置文件中的属性 保存到运行的环境变量中 加载完外部的配置文件以后再使用${}取出配置文件的值
@PropertySource(value={"classpath:/person.properties"})
public class MainConfigOfPropertyValues{
@Bean
public Person person(){

}
}

Person.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Person{
//使用@Value赋值
//基本数值
//可以写SpEL #{}
//可以写${} 取出配置文件中的值[properties](在运行环境变量里面的值)

@Value("zhangsan")
private String name;

@Value("#{20-2}")
private Integer age;
@Value("${person.nickName}")
private String NickName;
}

person.properties

1
person.nickName = xxx

IOCTest_LifeCycle.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class IOCTest_PropertyValue{

@Test
public void test01(){
//创建ioc容器
AnnotationConfigapplicationContext applicationContext new AnnotationConfigapplicationContext(MainConfigOfPropertyValues.class);
System.out.println("容器创建完成");
Person person = (Person)applicationContext.getBean("person");
ConfigurableEnvironment environment = applicationContext.getEnvironment();
String property = environment.getProperty("person.nickName");
System.out.println(property);
String[] definitionNames applicationContext.getBeanDefinitionName();
for(String name : definitionNames) {
System.out.println(name);
}
applicationContext.close();
}
}

自动装配

MainConfigAutowired.java

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
26
27
28
29
30
31
32
/*
* 自动装配
* Spring利用依赖注入(DI) 完成对IOC容器中各个组件的关系依赖赋值
* 1. AutoWired 自动注入
* 1. 默认优先按照类型去容器中找对应的组件,找到就赋值
* 2. 如果找到相同类型的组件,再将属性的名称作为组件的id去容器中查找
* applicationContext.getBean("bookDao")
* 3. @Qualifier("bookdao")使用@Qualifier指定需要装配的组件的id
* 4. 自动装配默认一定要将属性赋值好,没有就报错
* 5. Primary 让Spring进行自动装配的时候默认使用首选bean 这个时候不用Qualifier 但是也可以继续使用@Qualifier指定需要装配的bean的名字
* 2. Spring还支持使用@Resource(JSR250)@Inject(JSR330)[Java规范的注解]
* @Resource:
* 可以和Autowired一样实现自动装配功能,但是这个注解默认是按照组件名称进行装配 也可以使用@Resource(name="bookDao2")指定装配的bean
* 没有支持@Primary功能没有支持@Autowired(required=false)
* @Inject:
* 需要导入javax.inject的包,和Autowired功能一样
* @Autowired:Spring定义的:@Resource,@Inject都是java规范
* 3. @Autowired: 构造器 参数 方法 属性 都是从容器中获取参数组件的值
* 1. 标在方法位置 @Bean标注的方法,创建对象的时候 方法参数的值从容器中获取 默认不写也是一样的 都能自动装配
* 2. 标在构造器上 如果组件只有一个有参构造器,这个有参构造器的@Autowired可以省略,参数位置的组件还是能够自动从容器中获取
* 3. 放在参数位置上
* 4. 自定义组件想要用Spring容器底层的一些组件(ApplicationContext, BeanFactory)
* 自定义组件实现xxxAware 在创建对象的时候 会调用接口规定的方法注入相关组件 Aware
* 把Spring底层一些组件注入到自定义的bean中
* xxxAware 功能 使用xxxProcessor来处理
*/
@Configuration
@ComponentScan({"com.service","com.dao","com.controller"})
public class MainConfigAutowired{


}

Boss.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//默认加载ioc容器中的组件 容器启动会调用无参构造器创建对象,再进行初始化赋值等操作
@Component
public class Boss{
//@Autowired
private Car car;

@Autowired
public Boss(@Autowired Car car){
this.car = car;
}

//@Autowired //标注在方法上 Spring容器创建当前对象 就会调用方法 完成赋值
//方法使用的参数,自定义类型的值从ioc容器中获取
public void setCar(Car car){
this.car = car;
}
}

IOCTest_Autowired.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class IOCTest_Autowired{

@Test
public void test01(){
//创建ioc容器
AnnotationConfigapplicationContext applicationContext new AnnotationConfigapplicationContext(MainConfigAutowired.class);
System.out.println("容器创建完成");
BookService bookService = applicationContext.getBean(BookService.class);
System.out.println(bookService);
BookDao bookDao = applicationContext.getBean(BookDao.class);
//bookDao == bookService.bookDao;
applicationContext.close();
}
}

Profile

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
/*
* Profile
* spring 为我们提供的可以根据当前环境,动态的激活和切换一系列组件的功能
* 开发环境,测试环境,生产环境
* 数据源,(/A)(/B)(/C)
* @Profile 指定组件在哪个环境的情况下才能被注册到容器中,不指定 任何环境下都能注册这个组件
* 加了环境标识的bean,只有这个环境被激活的时候才能注册到容器 默认是default 环境
* 运行方法 添加运行参数 -Dspring.profiles.active=test
* 代码方法 使用无参构造器
* 1. 创建一个applicationContext
* 2. 设置需要激活的环境
* applicationContext.getEnvironment().setActiveProfiles("test","dev");
* 3. 注册主配置类
* applicationContext.register(MainConfigOfProfile.class);
* 4. 启动刷新容器
* applicationContext.refresh();
* 写在配置类上 只有是指定的环境的时候,整个配置类里面的所有配置才能开始生效
* 没有标注环境标识的bean在,任何环境下都是加载的
*/
@Configuration
@PropertySource("classpath:/dbconfig.proerties")
public class MainConfigOfProfile implements EmbeddedValueResolverAware{


@Value("db.user")
private String user;

private StringValueResolver valueResolver;

@Profile("dev")
@Bean("devDataSource")
public DataSource dataSourceDev(@Value(db.password) String pwd) {
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setUser(user);
dataSource.setPassword(password);
dataSource.setJdbcUrc(valueResolverresolveStringValue("${db.driveClass}"));
dataSource.setDriverClass("com.mysql.jdbc.Driver");
return null;
}

@Profile("test")
@Bean("testDataSource")
public DataSource dataSourceTest() {
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setUser("root");
dataSource.setPassword("123456");
dataSource.setJdbcUrc("jdbc:mysql://localhost:3306/");
dataSource.setDriverClass("com.mysql.jdbc.Driver");
return null;
}

@Profile("prod")
@Bean("prodDataSource")
public DataSource dataSourceProd() {
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setUser("root");
dataSource.setPassword("123456");
dataSource.setJdbcUrc("jdbc:mysql://localhost:3306/");
dataSource.setDriverClass("com.mysql.jdbc.Driver");
return null;
}

@Override
public void setEmbeddedValueResolver(StringValueResolver resolver) {
this.valueResolver = resolver;
}

}

dbconfig.proerties

1
2
3
db.user = root
db.password = 123456
db.driverClass = com.mysql.jdbc.Driver

MainConfigOfAOP.java

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
/*
* AOP [动态代理]
* 指在程序运行期间动态的将某段代码切入到指定方法指定位置进行运行的变成方式
* 1.导入AOP模块 springaop
* 2.定义一个业务逻辑类(MathCalculator) 在业务逻辑运行的时候将日志进行打印,在运行方法前 运行方法结束 方法出现异常的时候 -> 解耦合
* 3.定义一个日志切面类(LogAspects)切面类里面的方法需要动态感知MathCalculator运行到哪里然后执行
* 通知方法:
* 前置通知(@Before) -> logStart 在目标方法div运行之前运行
* 后置通知(@After) -> logEnd 在目标方法div运行结束之后运行 无论方法正常结束 异常结束 都调用
* 返回通知(@AfterReturning) -> logReturn 在目标方法div正常返回之后运行
* 异常通知(@AfterThrowing) -> logException 在目标方法运行出现异常以后运行
* 环绕通知(@Around) -> 动态代理, 手动推进目标方法运行(joinPoint.procced)
* 4.给切面类的目标方法标注何时何地运行 通知注解
* 5.将切面类和业务逻辑了(目标方法所在类)都加入到容器中
* 6.必须告诉spring哪个类是切面类(给切面类上加一个注解@Aspect)
* [7]给配置类中加入@EnableAspectJAutoProxy 开启基于注解的AOP模式
* 在spring中有很多的@Enablexxx 用于开启某些功能
* 三步
* 1) 将业务逻辑组件和切面类都加入到容器中 告诉spring哪个是切面类(@Aspect)
* 2) 在切面类上的每一个通知方法上标注通知注解 告诉spring何时何地运行(切入点表达式)
* 3) 开启基于注解的aop模式 @EnableAspectJAutoProxy
*
* AOP原理 [看给容器中注册了什么组件 这个组件什么时候工作 这个组件工作时候的功能是什么]
* @EnableAspectJAutoProxy;
* 1. @EnableAspectJAutoProxy是什么
* @Import(AspectJAutoProxyRegistar.class) 给容器中导入AspectJAutoProxyRegistar
* 利用AspectJAutoProxyRegistar自定义给容器中注册bean
* internalAutoProxyCreator=AnnotationAwareAspectJAutoProxyCreator
* 给容器中注册一个叫AnnotationAwareAspectJAutoProxyCreator
* 2. AnnotationAwareAspectJAutoProxyCreator
* -> AnnotationAwareAdvisorAspectJAutoProxyCreator
* -> AspectJAwareAdvisorAutoProxyCreator
* -> AbstractAdvisorAutoPorxyCreator
* -> AbstractAutoProxyCreator
* implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware
* 关注后置处理器(在bean初始化完成前后做事情),自动装配BeanFactory
*
*
* AbstractAutoProxyCreator.setBeanFactory()
* AbstractAutoProxyCreator 有后置处理器的逻辑
*
* AbstractAdvisorAutoPorxyCreator.setBeanFactory() -> initBeanFactory()
* AnnotationAwareAdvisorAspectJAutoProxyCreator.initBeanFactory()
* 流程
* 1) 传入配置类 创建ioc容器
* 2) 注册配置类 调用refresh 刷新容器
* 3) registerBeanPostProcessors(beanFactory);注册bean的后置处理器
* 1) 先获取ioc容器中已经定义了的要创建对象的所有BeanPostProcessor
* 2) 给容器中加入别的BeanPostProcessor
* 3) 优先注册实现了PriorityOrdered接口的BeanPostProcessor
* 4) 再给容器中注册实现了Ordered接口的BeanPostProcessor
* 5) 注册没实现优先级接口的BeanPostProcessor
* 6) 注册BeanPostProcessor 实际上是创建BeanPostProcessor对象 保存在容器中
* 创建internalAutoProxyCreator的BeanPostProcessor[AnnotationAwareAspectJAutoProxyCreator]
* 1)创建Bean的实例
* 2)populateBean 给bean的各种属性赋值
* 3)initializeBean 初始化bean
* 1) invokeAwareMethods 处理Aware接口的方法回调
* 2) applyBeanPostProcessorBeforeInitilization() 应用后置处理器的BeforeInitilization方法
* 3) invokeInitMethod 执行自定义的初始化方法
* 4) applyBeanPostProcessorBeforeInitilization 执行后置处理器的AfterInitilization方法
* 4)BeanPostProcessor(AnnotationAwareAspectJAutoProxyCreator)创建成功并且调用了他的 initBeanFactory方法 -> advisorbuilder
* 7) 把BeanPostProcessor注册到BeanFactory中
* beanFactory.addBeanPostProcessor(postProcessor)
*==============以上是创建和注册AnnotationAwareAspectJAutoProxyCreator的过程===========
* AnnotationAwareAspectJAutoProxyCreator => InstantiationAwareBeanPostProcessor
*
*
*/
@Configuration
@EnableAspectJAutoProxy
public class MainConfigOfAOP{

//业务逻辑加入类中
@Bean
public MathCalculator calculator(){
return new MathCalculator();
}

//切面类加入到容器中
@Bean
public LogAspects logAspects() {
return new LogAspects();
}
}

MathCalculator

1
2
3
4
5
6
public class MathCalculator{

public int div(int i, intj) {
return i/j;
}
}

LogAspects.java

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
26
27
28
29
30
//告诉spring当前类是切面类
@Aspect
public class LogAspects{

//抽取公共的切入点表达式
//1. 本类引用 直接在后面写@Before("pointCut()")
//2. 其他的切面类引用 使用方法全名
@PointCut("execution(public int com.aop.MathCalculator.*(..))")
public void pointCut(){};

//@Before在目标方法之前切入,切入点表达式(指定在哪个方法切入 可以使用通配符* means 所有方法 ..指定所有函数参数)
@Before("public int com.aop.MathCalculator.*(..)")
public void logStart(JoinPoint joinPoint){
Object[] args = joinPoint.getArgs();
System.out.println(joinPoint.getSignator().getName()+"运行除法"+Arrays.asList(args));
}
@After("pointCut()")
public void logEnd(){
System.out.println("除法结束");
}

//JoinPoint 一定要出现在参数表的第一位 @AfterReturning(value="pointCut()",returning="result")
public void logReturn(JointPoint joinPoint, Object result){
System.out.println("除法正常返回"+result);
}
@AfterThrowing(value="pointCut()", throwing="exception")
public void logExpection(Exception exception){
System.out.println("除法异常信息")
}
}