1,前言
学习雷老师的Spring注解版的学习笔记
有关AOP原理的初步学习,做此记录
若有不当之处,请您指出,您的指点是我的荣幸
2,AOP
2.1,示例
2.1.1,MathCaculator类
public class MathCaculator {
public int div(int i,int j){
System.out.println("这个方法被调用了MathCaculatoy...div...");
return i/j;
}
}
2.1.2,LogAspects类
/**
* 这是一个切面类,
* 存有一些在切点方法运行前后运行的方法
*
* @Aspect:告诉Spring,这是一个切面类,而不是一些其他的普通类
*
*
*/
@Aspect
public class LogAspects {
/**
* 由于下面的注解中,每一个都要写方法的全限定名,我们可以把其中的公共部分抽取出来
* 更多详情参见官方文档
* 使用@Pointcut
* 1,本类引用
* 2,其他的切面引用,就用全限定名
*/
@Pointcut("execution(public int com.cb414.aop.MathCaculator.*(..))")
public void pointCut(){};
//@Before在目标方法之前切入,;
//切入点表达式(指定在哪个方法进行切入):public int com.cb414.aop.MathCaculator.div(int,int)
@Before("pointCut()")
public void logStart(JoinPoint joinPoint){
//joinPoint.getSignature()是拿到方法的签名,
//joinPoint.getSignature().getName()拿到方法的名字
//拿到目标方法运行时要用的参数
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参数列表是{}");
}
//注意,参数中,JointPoint参数必须写在参数表的第一位,不能写在后面,否则Spring是不能识别的
@AfterReturning(value="pointCut()",returning = "result")
public void logReturn(JoinPoint joinPoint,Object result){
//注意,这里的returning是用来指定,这个方法使用谁来封装返回值
//这里是使用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()+"除法异常。。。@AfterThrowing异常信息是{}");
}
}
2.1.3,配置类
@EnableAspectJAutoProxy
@Configuration
public class MainConfigOfAop {
//将业务逻辑类加载到容器当中
@Bean
public MathCaculator mathCaculator(){
return new MathCaculator();
}
//切面类加入到容器当中
@Bean
public LogAspects logAspects(){
return new LogAspects();
}
}
2.1.4,测试类
public class IOCTestAOP {
@Test
public void test01(){
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(MainConfigOfAop.class);
//1,不要自己创建对象
//这样写,实际上是没有效果的,因为这是我们自己写的,而不是由容器执行的
//只有容器生成的那些bean对象执行方法才能够有aop的效果
//所以我们不能自己创建,应该要从容器中拿到那些bean
// MathCaculator mathCaculator = new MathCaculator();
// mathCaculator.div(1,1);
MathCaculator mathCaculator = annotationConfigApplicationContext.getBean(MathCaculator.class);
mathCaculator.div(1,1);
annotationConfigApplicationContext.close();
}
}
2.1.5,运行结果
div除法运行。。。@Before参数列表是{[1, 1]}
这个方法被调用了MathCaculatoy...div...
div除法结束。。。@After参数列表是{}
div除法正常返回。。。@AfterReturning参数列表是{1}
2.2,什么是AOP
AOP:【动态代理】
指在程序运行期间动态的将某段代码切入到指定方法指定位置进行运行的编程方式
2.3,步骤
- 导入aop模式:Spring AOP(要导入aop依赖)
- 定义一个业务逻辑类(MathCaculator);在业务逻辑运行的时候将日志进行打印(方法之前,方法结束之后)
- 定义一个日志切面类,(logAspects),切面类里面的方法需要动态的感知MathCaculator.div方法运行到哪里了,并执行对应的方法
- 给切面类的目标方法去标注何时何地运行(通知注解)
- 将切面类和业务逻辑类(目标方法所在的类)都加入到容器当中
- 必须告诉容器,哪个是切面类,也就是说,Spring容器不知道我们在主配置类加到容器中的那两个bean哪个是切面类,哪个是业务逻辑类。所以我们只需要给切面类加一个注解
- 需要给配置类中加入一个配置(@EnableAspectJAutoProxy),启用Aspect自动代理
开启基于注解的aop模式
这是最关键的一步,
在Spring中有很多的@EnableXXX;这些是用来开启某些功能的,非常重要
2.4,@EnableAspectJAutoProxy
重点就是研究一下这个注解:@EnableAspectJAutoProxy
aop的一切都要从这个注解入手
@EnableAspectJAutoProxy
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
//@Import({AspectJAutoProxyRegistrar.class})给容器中导入AspectJAutoProxyRegistrar.class
//因为AspectJAutoProxyRegistrar.class实现的是ImportBeanDefinitionRegistrar这个接口
//而ImportBeanDefinitionRegistrar这个接口是专门给容器中注册自定义实现的bean的
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
...
}
点进AspectJAutoProxyRegistrar,在registerBeanDefinitions()处打上断点,然后debug运行,查看它的工作流程
debug运行之后,会有这么一段代码
//这里的AUTO_PROXY_CREATOR_BEAN_NAME它的值是--》"internalAutoProxyCreator"
//这里的cls是--》AnnotationAwareAspectJAutoProxyCreator
private static BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls, BeanDefinitionRegistry registry, Object source) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
//判断容器之中是否有这个一个bean的定义信息,如果有就执行下列的操作
if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
int requiredPriority = findPriorityForClass(cls);
if (currentPriority < requiredPriority) {
apcDefinition.setBeanClassName(cls.getName());
}
}
return null;
}
//如果没有,就创建一个AnnotationAwareAspectJAutoProxyCreator类型的bean的定义信息
RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
beanDefinition.setSource(source);
beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
//将这个类型为AnnotationAwareAspectJAutoProxyCreator,
//bean名称为"internalAutoProxyCreator"的定义信息注册到容器当中
registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
return beanDefinition;
}
接下来就是研究下给容器中注册的这个AnnotationAwareAspectJAutoProxyCreator
通过查看源码,可以发现AnnotationAwareAspectJAutoProxyCreator的继承树
/**
AnnotationAwareAspectJAutoProxCreator
继承了AspectJAwareAdvisorAutoProxyCreator
AspectJAwareAdvisiorAutoProxyCreator
继承自AbstractAdvisiorAutoProxyCreator
AbstractAdvisiorAutoProxyCreator
继承自AbstractAutoProxyCreator
而AbstractAutoProxyCreator这个父类需要关注的是它实现了
SmartInstantiationAwareBeanPostProcessor.BeanFactoryAware
接下来我们需要在 AbstractAutoProxyCreator.setBeanFactory()打上【断点】
AbstractAutoProxyCreator.postProcessBeforeInstantiation()打上【断点】
AbstractAutoProxyCreator.postProcessAfterInitialization()打上【断点】
AbstractAdvisiorAutoProxyCreator.setBeanFactory()打上【断点】
AnnotationAwareAspectJAutoProxCreator.initBeanFactory()打上【断点】
mathCaculator,logAspects 【断点】
*/
打完断点之后继续debug运行
2.5,流程
研究一下AnnotationAwareAspectJAutoProxyCreator的创建和注册流程
2.5.1,传入配置类,创建IOC容器
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(MainConfigOfAop.class);
public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
this();
register(annotatedClasses);
refresh();
}
2.5.2,注册配置类,调用refresh()刷新容器
刷新容器就是相当于要把bean都创建好,类似于初始化
2.5.3,registerBeanPostProcessors(beanFactory);
注册bean的后置处理器来方便拦截bean的创建
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
......
try {
......
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
......
}
}
接下来就是研究一下registerBeanPostProcessors(beanFactory)这个方法
2.5.4,registerBeanPostProcessors(beanFactory)
public static void registerBeanPostProcessors(
ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {
//先获取容器中所有已经定义了需要创建对象的所有BeanPostProcessors
//这里之所以会有一些已经定义了的,是因为@EnableAspectJAutoProxy导入的AnnotationAwareAspectJAutoProxyCreator,它所继承的父类实现了SmartInstantiationAwareBeanPostProcessor接口,所以它也是一个后置处理器
//值得注意的是,@EnableAspectJAutoProxy导入的组件当初只是导入了一些bean的定义信息,而非实例化了一个bean出来
//详见图1
String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
//给容器中添加一些其他的BeanPostProcessor
int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));
// Separate between BeanPostProcessors that implement PriorityOrdered,
// Ordered, and the rest.
//翻译:分离那些实现了PriorityOrdered,Ordered接口的还有剩下的后置处理器
//实际上也就是优先级顺序,定义了这些后置处理器的工作优先级
List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<BeanPostProcessor>();
List<BeanPostProcessor> internalPostProcessors = new ArrayList<BeanPostProcessor>();
List<String> orderedPostProcessorNames = new ArrayList<String>();
List<String> nonOrderedPostProcessorNames = new ArrayList<String>();
for (String ppName : postProcessorNames) {
//如果是实现了PriorityOrdered接口的后置处理器
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
//这里会去容器中拿到那些实现了bean,但实际上,容器刚创建的时候还没有bean被创建,所以这里的getBean()实际上也就是去创建bean
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
priorityOrderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
//如果是实现了Ordered接口的后置处理器
else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
orderedPostProcessorNames.add(ppName);
}
//剩下的那些后置处理器
else {
nonOrderedPostProcessorNames.add(ppName);
}
}
// First, register the BeanPostProcessors that implement PriorityOrdered.
//优先注册实现了PriorityOrdered接口的
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);
// Next, register the BeanPostProcessors that implement Ordered.
//然后注册实现了Ordered接口的
List<BeanPostProcessor> orderedPostProcessors = new ArrayList<BeanPostProcessor>();
for (String ppName : orderedPostProcessorNames) {
//这里会去容器中拿到那些实现了bean,但实际上,容器刚创建的时候还没有bean被创建,所以这里的getBean()实际上也就是去创建bean
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<BeanPostProcessor>();
for (String ppName : nonOrderedPostProcessorNames) {
//这里会去容器中拿到那些实现了bean,但实际上,容器刚创建的时候还没有bean被创建,所以这里的getBean()实际上也就是去创建bean
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));
}
图1:
2.5.5,getBean()
接着去研究一下容器是怎么拿到bean的,没拿到的话又是怎么去进行创建的
继续debug下去,会发现这么一段代码:
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)
throws BeanCreationException {
// Instantiate the bean.
//实例化一个bean
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
Class<?> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);
mbd.resolvedTargetType = beanType;
......
// Initialize the bean instance.
//初始化一个bean
Object exposedObject = bean;
try {
//给bean的各种属性进行赋值
populateBean(beanName, mbd, instanceWrapper);
if (exposedObject != null) {
//初始化bean
//初始化操作很重要,因为postProcessor是在初始化前后操作的
//接下来就需要研究一下initializeBean,详见 2.5.6
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
}
catch (Throwable ex) {
if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
throw (BeanCreationException) ex;
}
else {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
}
}
......
}
2.5.6,initializeBean()
这里是初始化bean的相关操作
protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
invokeAwareMethods(beanName, bean);
return null;
}
}, getAccessControlContext());
}
else {
//处理Aware接口的方法回调
invokeAwareMethods(beanName, bean);
}
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
//应用后置处理器的BeforeInitialization
//这一步的原理:
//拿到所有的后置处理器,循环执行它们的BeforeInitialization()
//这个就是后置处理器初始化之前的调用
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
//执行自定义的初始化方法
//也就是我们用@Bean注解的时候指定初始化方法
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()) {
//应用后置处理器的AfterInitialization
//这一步的原理:
//拿到所有的后置处理器,循环执行它们的AfterInitialization()
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
到了这一步,AnnotationAwareAspectJAutoProxCreator这个PostProcessor就创建和注册成功了
更多需要深入的原理–》AOP的工作原理