0%

Spring注解

回顾和深入注解使用.

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
26
27
package com.company.config;

import com.company.bean.Person;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Service;

import static org.springframework.context.annotation.ComponentScan.*;

/**
* @author xianzheTM
* @version 1.0
* @date 2020/7/17 19:54
*/
@Configuration
@ComponentScan(value = "com.company", excludeFilters = {
@Filter(type = FilterType.ANNOTATION, classes = {Controller.class, Service.class})
})
public class MainConfig {
@Bean
public Person person() {
return new Person("李四", 20);
}
}

这是一个Spring的注解类,用Configuration这个注解表明它是注解类.ComponentScan注解用来扫描Bean,excludeFilters设置了排除扫描范围内的哪些内容,type = FilterType.ANNOTATION表示根据注解排除,classes = {Controller.class, Service.class}表示排除Controller,Service注解.类似的还有includeFilters设置只包含哪些类型,但是这又需要另一个配置useDefaultFilters.该配置设为false,将默认的过滤规则禁用.

@Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {BookService.class})另一种过滤方式:按照指定类型,包括指定类型的子类,实现类在内.

还有按照AspectJ表达式和正则表达式过滤,但不常用.最后还有自定义过滤方式.

下面使用Bean注解单独注入了一个类,Bean后面可以添加value设置Bean的id.默认为下面的方法名.

此外,配置类本身也是一个Component,它是必须被加载的,无论如何过滤不掉的.

ComponentScan注解本身是一个可重复注解,也就是说可以写多个(需要Java8).此外还有一个ComponentScans注解,它的值是一个ComponentScan数组.

现在演示自定义过滤方式:

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
package com.company.config;

import org.springframework.core.io.Resource;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.ClassMetadata;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.filter.TypeFilter;

import java.io.IOException;

/**
* @author xianzheTM
* @version 1.0
* @date 2020/7/17 21:09
*/
public class MyTypeFilter implements TypeFilter {
/**
* @param metadataReader 读取到的当前正在扫描的类的信息
* @param metadataReaderFactory 获取的其它任何类的信息
*/
@Override
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
//获取当前类注解的信息
AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
//获取当前类的类信息
ClassMetadata classMetadata = metadataReader.getClassMetadata();
//获取当前类资源(类路径等)
Resource resource = metadataReader.getResource();
String className = classMetadata.getClassName();
System.out.println("->"+className);
if (className.contains("er")) {
return true;
}
return false;
}
}

自定义过滤需要实现TypeFilter接口,只有返回true才代表当前扫描的类匹配规则,加入容器.

测试一下:

1
2
3
4
5
6
@Test
public void test1() {
ApplicationContext context = new AnnotationConfigApplicationContext(MainConfig.class);
String[] names = context.getBeanDefinitionNames();
Arrays.stream(names).forEach(System.out::println);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
->com.company.bean.PersonTest
->com.company.config.MainConfigTest
->com.company.bean.Person
->com.company.config.MyTypeFilter
->com.company.controller.BookController
->com.company.dao.BookDao
->com.company.service.BookService
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
mainConfig
personTest
person
myTypeFilter
bookController
bookService

这是结果.可以看到扫描了包里的类,然后把spring自身需要的bean和配置类,带er的类都加入容器.此外这个自定义过滤也加入了容器.

此外,在Spring中Bean默认是单例的,当然可以手动设置作用域.

通过Scope这个注解来实现,主要用到其中两个值:prototype,singleton(默认).前者是多实例,后者是单实例.

另外单实例的默认情况下,Bean在容器启动时就创建.而多实例时,显示获取Bean时才会创建.

对于单实例,可以让其懒加载,即第一次使用Bean时再创建Bean.只需要加上Lazy这个注解.

Spring4中还提供了另一种加载Bean的方式:按照条件加载.

需要用到Conditional这个注解,这个注解中需要Condition这个值,这是一个自定义的条件类,需要实现Condition这个接口,然后实现里面的match方法,根据方法返回的Boolean值表示是否符合条件.

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
package com.company.config;

import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotatedTypeMetadata;

/**
* @author xianzheTM
* @version 1.0
* @date 2020/7/18 11:09
*/
public class WindowsCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
//获取ioc使用的BeanFactory
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
//获取类加载器
ClassLoader classLoader = context.getClassLoader();
//获取环境
Environment environment = context.getEnvironment();
//获取Bean定义的注册类
BeanDefinitionRegistry registry = context.getRegistry();

String property = environment.getProperty("os.name");
assert property != null;
return property.contains("Windows");
}
}

对于导入第三方包作为组件,还可以使用import快速导入.具体方法是在配置类上加一个Import注解:@Import(导入的类.class),这个注解的值也可以是一个数组,一次导入多个类.Import导入的Bean名字默认是全类名.

此外还可以在Import里导入一个ImportSelector.它需要一个实现了ImportSelector接口的实现类.需要实现selectImports方法,该方法返回一个String数组,该数组为要导入的全类名.

另外也可以导入自定义导入方式:

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
package com.company.config;

import com.company.bean.RainBow;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;

/**
* @author xianzheTM
* @version 1.0
* @date 2020/7/18 14:03
*/
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
/**
* @param importingClassMetadata 导入的当前类的注解信息
* @param registry 注册类
*/
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
boolean red = registry.containsBeanDefinition("com.company.bean.Red");
boolean yellow = registry.containsBeanDefinition("com.company.bean.Yellow");
//如果有这两个bean
if (red && yellow) {
//指定bean名
registry.registerBeanDefinition("rainbow", new RootBeanDefinition(RainBow.class));
}
}
}

然后将这个自定义类加入Import注解即可.

BeanFactory:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class MyBean implements FactoryBean<Book> {
//定义返回bean
@Override
public Book getObject() throws Exception {
Book book = new Book();
book.setAuthor("aa");
return book;
}

//定义返回类型
@Override
public Class<?> getObjectType() {
return Book.class;
}

//定义是否是单例
@Override
public boolean isSingleton() {
return false;
}
}

Bean的生命周期

以前对于Bean的初始化方法和销毁方法需要在xml中指定:

1
2
3
<bean id="order" class="com.company.test.Orders" init-method="init" destroy-method="destroy">
<property name="name" value="手机"></property>
</bean>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class Orders {
private String name;

public Orders() {
System.out.println("无参构造方法");
}

public void setName(String name) {
this.name = name;
System.out.println("set设置值");
}

public void init(){
System.out.println("初始化方法");
}

public void destroy(){
System.out.println("销毁");
}
}

现在换用注解只需要在@Bean的值里面添加initMethod=”init”,destroyMethod=”destroy”.

注意,对于多实例的Bean,IOC容器只负责创建,不负责管理销毁,因此销毁要自己来.

除了在Bean指定方法外,还可以使用InitializingBean接口

1
2
3
4
5
6
7
8
9
10
11
public interface InitializingBean {

/**
* Invoked by the containing {@code BeanFactory} after it has set all bean properties
* and satisfied {@link BeanFactoryAware}, {@code ApplicationContextAware} etc.
* <p>This method allows the bean instance to perform validation of its overall
* configuration and final initialization when all bean properties have been set.
* @throws Exception in the event of misconfiguration (such as failure to set an
* essential property) or if initialization fails for any other reason
*/
void afterPropertiesSet() throws Exception;

这个接口的方法会在BeanFactory创建完对象并设置好属性后执行,相当于上面的初始化方法.与之类似的销毁时的接口如下:

1
2
3
4
5
6
7
8
9
10
public interface DisposableBean {

/**
* Invoked by the containing {@code BeanFactory} on destruction of a bean.
* @throws Exception in case of shutdown errors. Exceptions will get logged
* but not rethrown to allow other beans to release their resources as well.
*/
void destroy() throws Exception;

}

这两个接口的具体用法是在某一个Bean的类中实现这两个接口和这两个方法.

现在还有第三种方式:使用@PostConstruct注解.该注解直接标注在方法上,用来做Bean属性赋值完成后做初始化方法.与之相对的是@PreDestroy注解.

此外还有一种特别的方式是使用BeanPostProcessor接口,Bean的后置处理器.它是用来对上面的初始化方法做处理.

postProcessBeforeInitialization:方法在初始化方法之前工作

postProcessAfterInitialization:方法在初始化方法之后工作

这里的初始化方法指上面三种都算在内.其具体原理是:

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
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
invokeAwareMethods(beanName, bean);
return null;
}, getAccessControlContext());
}
else {
invokeAwareMethods(beanName, bean);
}

Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}

try {
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}

return wrappedBean;
}

这是AbstractAutowireCapableBeanFactory.java的源码.从第13行开始它先执行了applyBeanPostProcessorsBeforeInitialization,然后在try中执行了初始化方法,接着执行了applyBeanPostProcessorsAfterInitialization.

这两个方法内部是:

1
2
3
4
5
6
7
8
9
10
11
12
13
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
throws BeansException {

Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessBeforeInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}

遍历所有BeanPostProcessor然后挨个执行,一旦方法返回null则跳出执行.

反向溯源,在doCreateBean方法中:

1
2
3
4
try {
populateBean(beanName, mbd, instanceWrapper);
exposedObject = initializeBean(beanName, exposedObject, mbd);
}

populateBean先给属性赋值,然后再初始化.

为Bean的属性赋值可以使用value注解.使用该注解时可以直接赋值基本类型,也可以使用SpEL表达式(#{20-2})这种形式,也可以使用$来取配置文件中的值.为了使用配置文件,还需要在配置类上加上PropertySource注解,该注解可以赋值一个配置文件数组.

自动注入

Autowired自动注入,默认按类型去容器中找对应的组件,如果找到了多个同类型的组件就会把属性的名字作为id去查找组件.当然也可以使用Qualifier注解装配指定的组件id.也可以在Bean上使用Primary注解表示该Bean是首选的.当然,使用Qualifier来明确指定装配的Bean时,这种指定”首选”的方式就失效.

对于Autowired注入的组件必须是包含在容器中的,如果容器里不存在,就会报错.不过也可以添加required=false表示该组件不是必须的.

与Autowired类似的还有Resource和Inject注解(这两个注解属于Java规范,而不是Spring).具体来说,Resource功能和Autowired类似能够自动装配,默认是按照组件名称装配.

Inject注解使用需要导入依赖,功能和Autowired 类似.

Autowired注解不仅可以用来直接加在属性上来注入,还可以用setter方法注入,另外也可以放在构造器上.放在构造器上时,不仅可以放在方法上,也可以放在参数上.当某个Bean只有一个有参构造器,则这个有参构造器可以省略Autowired,参数上的Bean可以自动获取.

当用Bean标注一个方法,该方法参数所需的组件也能自动从容器中获取.

综上,构造器里和Bean注解标注的方法里都不需要写Autowired.


如果需要在自定义的组件中调用Spring容器底层的一些组件,如ApplicationContext,BeanFactory等,则需要自定义组件实现对应的xxxAware接口,在创建自定义组件对象时,会调用接口规定的方法注入相关组件.

1
2
3
4
5
6
7
8
9
public class Red implements ApplicationContextAware {
private ApplicationContext applicationContext;

@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
System.out.println(applicationContext);
this.applicationContext = applicationContext;
}
}

如上所示,Red这个Bean实现ApplicationContextAware接口,通过接口内的方法拿到了applicationContext.

每个xxxAware都对应着xxxAwareProcessor,即后置处理器.以ApplicationContextAwareProcessor为例,它实现了BeanPostProcessor接口.该类有个方法如下:

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
@Override
@Nullable
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (!(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)){
return bean;
}

AccessControlContext acc = null;

if (System.getSecurityManager() != null) {
acc = this.applicationContext.getBeanFactory().getAccessControlContext();
}

if (acc != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
invokeAwareInterfaces(bean);
return null;
}, acc);
}
else {
invokeAwareInterfaces(bean);
}

return bean;
}

该方法开始是判断Bean是不是实现了xxxAware接口,接下来是一些权限判断.最主要的是最后invokeAwareInterfaces方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
private void invokeAwareInterfaces(Object bean) {
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);
}
}

现在是ApplicationContextAware,也就是最后一个,所以调用set方法传入了ApplicationContextAware这个Bean.

Profile

profile是Spring提供的可以根据当前环境,动态的激活和切换一系列组件的功能.

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
package com.company.config;

import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.springframework.beans.factory.annotation.Value;
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 javax.sql.DataSource;
import java.beans.PropertyVetoException;

/**
* @author xianzheTM
* @version 1.0
* @date 2020/7/19 11:00
*/
@PropertySource("classpath:/jdbc.properties")
@Configuration
public class MainConfigProfile {
@Value("${user}")
private String user;

@Profile("test")
@Bean
public DataSource dataSourceTest(@Value("${password}") String pwd) throws PropertyVetoException {
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test?serverTimezone=GMT");
dataSource.setUser(user);
dataSource.setPassword(pwd);
dataSource.setDriverClass("com.mysql.cj.jdbc.Driver");
return dataSource;
}

@Profile("dev")
@Bean
public DataSource dataSourceDev(@Value("${password}") String pwd) throws PropertyVetoException {
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/book?serverTimezone=GMT");
dataSource.setUser(user);
dataSource.setPassword(pwd);
dataSource.setDriverClass("com.mysql.cj.jdbc.Driver");
return dataSource;
}
}

现在有两个Profile,分别是test和dev(名字随便).如果某个Bean不指定Profile,那么任何环境都能注册这个组件.

第一种切换环境的方式:在运行的配置中加入vm参数-Dspring.profile.active=环境名

第二种用代码实现,先看下原来用ApplicationContext context = new AnnotationConfigApplicationContext(MainConfig2.class);的代码:

1
2
3
4
5
public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
this();
register(componentClasses);
refresh();
}

可以看到这种方式是先调用无参构造器,然后注册配置类,然后刷新.现在使用Profile就是在注册前加一步:

1
2
3
4
5
6
7
8
9
10
11
12
13
@Test
public void test1() {
//创建一个context
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
//设置需要激活的环境
context.getEnvironment().setActiveProfiles("test", "dev");
//注册主配置类
context.register(MainConfigProfile.class);
//启动刷新容器
context.refresh();
String[] names = context.getBeanDefinitionNames();
Arrays.stream(names).forEach(System.out::println);
}

Profile注解不仅可以加在方法上用来动态添加Bean,也可以直接写在配置类上.只有是指定环境时才会加载配置类.

AOP

首先写切面类:

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
package com.company.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;

import java.util.Arrays;

/**
* @author xianzheTM
* @version 1.0
* @date 2020/7/19 14:33
*/
@Aspect
public class LogAspects {
//若是在别的地方要用切点,则要写全类名;本类使用只要写方法名
@Pointcut("execution(public int com.company.aop.MathCalculator.*(..))")
public void pointCut() {
}

@Before("pointCut()")
public void logStart(JoinPoint joinPoint) {
Object[] args = joinPoint.getArgs();
System.out.println(joinPoint.getSignature().getName() + "运行...@Before参数列表是:{" + Arrays.asList(args) + "}");
}

@After("pointCut()")
public void logEnd(JoinPoint joinPoint) {
System.out.println(joinPoint.getSignature().getName() + "结束...@After");
}

//joinpoint参数必须要放在第一位
@AfterReturning(value = "pointCut()", returning = "result")
public void logReturn(JoinPoint joinPoint, Object result) {
System.out.println(joinPoint.getSignature().getName() + "正常返回...@AfterReturning运行结果是:{" + result + "}");
}

@AfterThrowing(value = "pointCut()", throwing = "exception")
public void logException(JoinPoint joinPoint, Exception exception) {
System.out.println(joinPoint.getSignature().getName() + "异常...异常信息是:{" + exception + "}");
}
}

注意加@aspect注解,表示这是一个注解类.其中After通知是在方法结束后进行,不论方法是否正常执行.AfterReturning是在方法正常返回后执行.

在配置类中还要通过注解开启AOP:

1
2
3
4
5
6
7
8
9
10
11
12
13
@EnableAspectJAutoProxy
@Configuration
public class MainConfigAOP {
@Bean
public MathCalculator calculator() {
return new MathCalculator();
}

@Bean
public LogAspects logAspects() {
return new LogAspects();
}
}

@EnableAspectJAutoProxy该注解实际导入了AspectJAutoProxyRegistrar这个Bean:

20200719174233

这个类的代码如下:

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
class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {

/**
* Register, escalate, and configure the AspectJ auto proxy creator based on the value
* of the @{@link EnableAspectJAutoProxy#proxyTargetClass()} attribute on the importing
* {@code @Configuration} class.
*/
@Override
public void registerBeanDefinitions(
AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);

AnnotationAttributes enableAspectJAutoProxy =
AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
if (enableAspectJAutoProxy != null) {
if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
}
}
}

}

该类的方法传入了一个BeanDefinitionRegistry,这个Bean前面用来自定义注册Bean,这里的用处也是如此.

该方法的第一行调用了AopConfigUtils的registerAspectJAnnotationAutoProxyCreatorIfNecessary方法,看方法名知道它(如果必要)注册了AspectJAnnotationAutoProxyCreator.根据方法调用栈:

20200719201938

它来到这个方法:

1
2
3
4
5
6
@Nullable
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(
BeanDefinitionRegistry registry, @Nullable Object source) {

return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
}

registerOrEscalateApcAsRequired表示如果需要就注册或逐步升级.方法传入了AnnotationAwareAspectJAutoProxyCreator.class.具体看这个方法:

20200719204221

可以看到这里使用cls作为参数名表示AnnotationAwareAspectJAutoProxyCreator.class.紧接着做了一个判断,判断是否包含一个特定的Bean:

20200719210613

它判断了一下是否包含internalAutoProxyCreator,现在是第一次运行,不包含.直接看后面:

用cls创建了一个RootBeanDefinition,即Bean的定义信息.接着将Bean的定义信息和Bean的名字注册:

image-20200719213523141

最终注册了一个internalAutoProxyCreator的Bean定义,这个Bean定义具体是cls,即AnnotationAwareAspectJAutoProxyCreator.

image-20200719215918229

查看AnnotationAwareAspectJAutoProxyCreator的类间关系:

image-20200719221156187

可以看到该类即实现了SmartInstantiationAwareBeanPostProcessor接口,又实现了BeanFactoryAware接口.现在搞明白这个类实现这两个接口干了什么就知道AOP怎么实现的了.

查看AbstractAutoProxyCreator这个类的实现,只关注和BeanFactory和后置处理器相关的内容,并打上断点(有些是空方法,不管):

image-20200719222443746

从父类来到子类,发现setBeanFactory方法被重写了,里面调用了initBeanFactory方法.

image-20200719222819497

来到AnnotationAwareAspectJAutoProxyCreator发现initBeanFactory方法被重写了,说明上面调用的实际是这里的方法.为这几个关键方法打上断点debug一下.

image-20200719224916953

先从传入配置类,创建IOC容器开始.

image-20200719223851657

上面提过,注册配置类,调用refresh刷新容器.

在refresh方法里是注册bean后置处理器来拦截Bean的创建:image-20200719224343974

在第四步中用到的方法第一行是这样的代码:

1
String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);

获取了IOC容器中已经定义的需要创建对象的所有BeanPostProcessor.因为spring自身有一些默认的后置处理器,.外加如上面分析的那样,@EnableAspectJAutoProxy这个注解使得创建容器时定义了internalAutoProxyCreator (实际Bean定义是AnnotationAwareAspectJAutoProxyCreator).但此时只是定义了,还没有被创建.

image-20200719230543268

可以看到internalAutoProxyCreator和另一个Processor要被创建.(照理说应该不止两个的).这个方法的完整代码:

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
public static void registerBeanPostProcessors(
ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {

String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);

// Register BeanPostProcessorChecker that logs an info message when
// a bean is created during BeanPostProcessor instantiation, i.e. when
// a bean is not eligible for getting processed by all BeanPostProcessors.
int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));

// Separate between BeanPostProcessors that implement PriorityOrdered,
// Ordered, and the rest.
List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
List<BeanPostProcessor> internalPostProcessors = new ArrayList<>();
List<String> orderedPostProcessorNames = new ArrayList<>();
List<String> nonOrderedPostProcessorNames = new ArrayList<>();
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
priorityOrderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
orderedPostProcessorNames.add(ppName);
}
else {
nonOrderedPostProcessorNames.add(ppName);
}
}

// First, register the BeanPostProcessors that implement PriorityOrdered.
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);

// Next, register the BeanPostProcessors that implement Ordered.
List<BeanPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
for (String ppName : orderedPostProcessorNames) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
orderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
sortPostProcessors(orderedPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, orderedPostProcessors);

// Now, register all regular BeanPostProcessors.
List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
for (String ppName : nonOrderedPostProcessorNames) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
nonOrderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);

// Finally, re-register all internal BeanPostProcessors.
sortPostProcessors(internalPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, internalPostProcessors);

// Re-register post-processor for detecting inner beans as ApplicationListeners,
// moving it to the end of the processor chain (for picking up proxies etc).
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
}

主要分为两部分,先将postProcessorNames数组里的PostProcessor分类,按照priorityOrderedPostProcessors,orderedPostProcessorNames,nonOrderedPostProcessorNames等,划分依据是看它是否实现了PriorityOrdered和Ordered接口(19行和26行).

在debug中,现在代码来到41行.这就验证了上面的逻辑,internalAutoProxyCreator在orderedPostProcessorNames这个数组里.前面说过,

internalAutoProxyCreator的定义是AnnotationAwareAspectJAutoProxyCreator,而查看上面的关系图可知它确实实现了Ordered接口.

接着研究getBean这个方法,看其调用栈,掠过中间过程来到11.发现停在一个巨大的方法中,这里先看调用其它方法的地方:

image-20200720144726937

注释写明这是初始化Bean实例的意思.那么倒推前面应该有创建Bean的地方:

image-20200720145003733

果然找到了创建Bean的地方(Instantiate实例化的意思).createBeanInstance方法的前两个参数值:

image-20200720145152819

image-20200720145223593

这不就和前面的对上了.

回到初始化Bean的地方,populateBean方法是给Bean的属性赋值(populate意思是填充).属性赋值完成后就是初始化Bean(initializeBean方法).查看这个初始化方法,发现它调用了invokeAwareMethods方法.

image-20200720150339620

先不管invokeAwareMethods方法,看看这个方法下面是什么:

image-20200720150521548

老朋友又来了,使用在初始化之前的后置处理器方法.点开这个方法看看:

image-20200720150759158

这不就是前面提过的AbstractAutowireCapableBeanFactory中的方法.遍历后置处理器并调用后置处理器的前置方法(初始化前的方法).

回到initializeBean方法,在这个apply方法后面是执行了invokeInitMethods方法.确实按照上面的逻辑,前置方法完了就该轮到初始化方法.初始化方法完了就是后置处理器的后置方法了.一看代码确实如此:

image-20200720151517109

这几步是初始化和初始化的前置后置处理,那么Bean的创建前面已经有了,属性赋值也有了,这里清楚后回到开始的invokeAwareMethods.这里调用了setBeanFactory方法,这个setBeanFactory方法就是一开始所说被重写的那个setBeanFactory方法.这里被重写最主要的就是添加了一个initBeanFactory方法,该方法具体为:

image-20200720161918816

主要是初始化BeanFactory.

至此,后置处理器创建完成.registerBeanPostProcessors方法的第四十一行终于执行完.

image-20200720162843535

接着把后置处理器排了个序,然后注册.所谓的注册也就是让BeanFactory添加Bean:

image-20200720163057424

而这里现在实际只有一个后置处理器,即AnnotationAwareAspectJAutoProxyCreator.这就是现在我们需要的东西.

未完