Spring注解驱动开发4:AOP使用和原理
Spring注解驱动开发系列:
Spring注解驱动开发4:AOP使用和原理
使用AOP
最后来看一下使用AOP的方式,假设我们需要对函数进行日志记录:
第一件事,在pom中导入依赖:
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.18.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.10</version>
</dependency>
先定一个功能类:
@Component
public class MathCalculator {
public int div(int i, int j) {
return i / j;
}
}
然后定义日志切面类:
@Aspect
@Component
public class LogAspects {
//定义统一的切入点
@Pointcut("execution(public int com.lin.springL.aop.MathCalculator.*(..))")
public void pointCut() {
}
//可以直接指向方法
@Before("execution(public int com.lin.springL.aop.MathCalculator.*(..))")
public void logStart(JoinPoint joinPoint) {
//JoinPoint会被自动传入,里面包含了很多信息
Object[] args = joinPoint.getArgs();
System.out.println("logStart..., args:{" + Arrays.asList(args) + "}");
}
//可以使用定义的统一的切入点
@After("pointCut()")
public void logEnd() {
System.out.println("logEnd...");
}
//使用returning指定返回值参数
@AfterReturning(value = "pointCut()", returning = "result")
public void logReturn(Object result) {
System.out.println("logReturn..., result:{" + result + "}");
}
//外部类也可以使用本类定义的统一切入点
@AfterThrowing(value = "com.lin.springL.aop.LogAspects.pointCut()", throwing = "e")
public void logEcxeption(Exception e) {
System.out.println("logException..., excpetion:{" + e.getMessage() + "}");
}
}
编写配置类:
//配置类==配置文件
@Configuration
//开启自动包扫描,传入要扫描的包路径
@ComponentScan(basePackages = "com.lin.springL")
//开启自动代理
@EnableAspectJAutoProxy
public class MainConfigure {
}
编写主测试类:
public class MainTest {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new
AnnotationConfigApplicationContext(MainConfigure.class);
MathCalculator bean = applicationContext.getBean(MathCalculator.class);
int div = bean.div(3, 3);
System.out.println(div);
}
}
运行得到输出如下:
logStart..., args:{[3, 3]}
logEnd...
logReturn..., result:{1}
1
AOP原理
从上面可以看出要使用AOP,需要在Spring配置类中增加注解@EnableAspectJAutoProxy
,因此以这个注解为入口,进入查看:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
发现其使用了@Import(AspectJAutoProxyRegistrar.class)
向容器中注册了AspectJAutoProxyRegistrar
这个类,所以进入到这个类查看:
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) {
//注册AspectJAnnotationAutoProxyCreator
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
AnnotationAttributes enableAspectJAutoProxy =
AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
}
}
}
这个类中只有一个registerBeanDefinitions方法,这个方法中主要注意到AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
向容器中注入了AspectJAnnotationAutoProxyCreator这个类,这个就是AOP的核心,接下来主要就是要理解这个=组件是做什么,什么时候工作。
AspectJAnnotationAutoProxyCreator
从关系图上关注到两点:
- AspectJAnnotationAutoProxyCreator实现了BeanPostProcessor后置处理器,在Bean初始化完成前后做事情。
- AspectJAnnotationAutoProxyCreator实现了BeanFactoryAware,自动装配BeanFactory。
到这大概可以猜测是向容器中注入AspectJAnnotationAutoProxyCreator后,当Bean对象创建后会被AspectJAnnotationAutoProxyCreator所增强,也就是实现该Bean的代理。
AspectJAnnotationAutoProxyCreator实现BeanPostProcessor中的方法如下:
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
Object cacheKey = getCacheKey(beanClass, beanName);
if (beanName == null || !this.targetSourcedBeans.contains(beanName)) {
if (this.advisedBeans.containsKey(cacheKey)) {
return null;
}
if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return null;
}
}
// Create proxy here if we have a custom TargetSource.
// Suppresses unnecessary default instantiation of the target bean:
// The TargetSource will handle target instances in a custom fashion.
if (beanName != null) {
TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
if (targetSource != null) {
this.targetSourcedBeans.add(beanName);
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
}
return null;
}
看到Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
创建了代理对象并返回,所以对应的Bean已经被增强为代理类。
本文来自博客园,作者:林老头儿,转载请注明原文链接:https://www.cnblogs.com/jinchengll/p/12922336.html