一、spring AOP 和 AspectJ
spirng AOP: 是基于对象代理模式进行织入逻辑代码,但对于static和final方法上应用织入是无法做到的
AspectJ :其是一个独立的在编辑期进行逻辑代码的织入框架,不受限于必须获取代理
二、AOP织入
1. Advice、Pointcut、Advisor、ProxyFactory
Advice (通知)是AOP联盟定义的一个接口,描述了连接点做什么,为切面增强提供织入接口。编写逻辑代码的基类
Pointcut (切点)决定Advice通知应该作用于哪个连接点。也就是说这些连接点集合(决定切入的方法)是通过Pointcut来决定的
Advisor (通知器)是对Advice和Pointcut的整合,作为IoC容器使用AOP的基础设施。所有
ProxyFactory(生成代理对象的工厂类)可以让我们通过编程式的方法实现spirng AOP功能
在spring中有三个代理工厂类,除了上面提到的还有ProxyFactoryBean(声明式应用)、AspectJProxyFactory(AspectJ应用),它们都继承了ProxyCreatorSupport类
2. 应用演示
目标类,提供切入点
class TargetImpl {
public void print() {
System.out.println("this is target");
}
}
MethodInterceptor
MethodInterceptor是一个最基础的继承自->Interceptor->Advice的通知类。ProxyFactory生成bean代理有jdk proxy和Cglib两种方式,但spirng把它们的回调都统一封装,回调执行MethodInterceptor的invoke方法
具体封装在了ReflectiveMethodInvocation里,执行process来调起invoke
private static void basics() {
Advice advice = (MethodInterceptor) (invocation) -> {
System.out.println("enter advice->interceptor->methodInterceptor");
return invocation.proceed();
};
Pointcut pointcut = new Pointcut() {
@Override
public ClassFilter getClassFilter() {
return ClassFilter.TRUE;
}
@Override
public MethodMatcher getMethodMatcher() {
return MethodMatcher.TRUE;
}
};
Advisor advisor = new DefaultPointcutAdvisor(pointcut, advice);
ProxyFactory proxyFactory = new ProxyFactory(new TargetImpl());
proxyFactory.addAdvisor(advisor);
TargetImpl target = (TargetImpl) proxyFactory.getProxy();
target.print();
}
代码中出现的DefaultPointcutAdvisor是spirng提供的一个默认通知器
MethodBeforeAdviceInterceptor、AfterReturningAdviceInterceptor
private static void before() {
Advice advice = new MethodBeforeAdviceInterceptor((method, objects, o) -> System.out.println("enter before advice"));
ProxyFactory proxyFactory = new ProxyFactory(new TargetImpl());
proxyFactory.addAdvice(advice);
TargetImpl target = (TargetImpl) proxyFactory.getProxy();
target.print();
}
private static void after() {
Advice advice = new AfterReturningAdviceInterceptor((rv, method, objects, o) -> System.out.println("enter after advice"));
ProxyFactory proxyFactory = new ProxyFactory(new TargetImpl());
proxyFactory.addAdvice(advice);
TargetImpl target = (TargetImpl) proxyFactory.getProxy();
target.print();
}
ProxyFactory虽然可以直接添加Advice,但这并不表示它不需要Ponitcut的实现。阅读add方法源码可以看到它会生成一个默认的DefaultPointcutAdvisor添加在addAdvisor列表里
@Override
public void addAdvice(int pos, Advice advice) throws AopConfigException {
Assert.notNull(advice, "Advice must not be null");
if (advice instanceof IntroductionInfo) {
// We don't need an IntroductionAdvisor for this kind of introduction:
// It's fully self-describing.
addAdvisor(pos, new DefaultIntroductionAdvisor(advice, (IntroductionInfo) advice));
}
else if (advice instanceof DynamicIntroductionAdvice) {
// We need an IntroductionAdvisor for this kind of introduction.
throw new AopConfigException("DynamicIntroductionAdvice may only be added as part of IntroductionAdvisor");
}
else {
addAdvisor(pos, new DefaultPointcutAdvisor(advice)); //创建默认Advisor
}
}
AspectJExpressionPointcut
spring通过AspectJExpressionPointcut来定义实现AspectJ中的切点语言
private static void aspectjBefore() {
TargetImpl target = new TargetImpl();
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
pointcut.setExpression("execution( * com.programmatic.springprogrammatic.TargetImpl.print(..) )");
Advice advice = new MethodBeforeAdviceInterceptor(new MethodBeforeAdvice() {
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println("enter before advice");
}
});
Advisor advisor = new DefaultPointcutAdvisor(pointcut, advice);
ProxyFactory proxyFactory = new ProxyFactory(target);
proxyFactory.addAdvisor(advisor);
TargetImpl proxyTarget = (TargetImpl) proxyFactory.getProxy();
proxyTarget.print();
}
结语
spring AOP可以说是通过两个流程来实现对代码的切入和执行逻辑代码。
(1)通知器的装配;spring AOP会把要切入点的位置和逻辑代码封装为一个标准调用流程。
(2)生成代理类的时候注入通知器;这样代理类在回调方法时就会运行切入逻辑代码了。
编程式的实现spring AOP是最基础的运用,它可以更好的使我们看到实现spring AOP装配过程,为更好的理解spring AOP作为一个基础篇
github地址:https://github.com/lotusfan/spring-programmatic ->ProxyFactoryTest
网友评论