主启动类
@EnableAspectJAutoProxy
@ComponentScan("com.jw.springframework.g_aop")
public class AopMain {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AopMain.class);
Caculate caculate = context.getBean(Caculate.class);
System.out.println(caculate.add(1, 2));
/* ProgramCaculate programCaculate = context.getBean(ProgramCaculate.class);
System.out.println(programCaculate.logicalAnd(16, 15));*/
}
}
切面类以及切面类内部设置pointcut切点和两个advice通知, before和after
@Component
@Aspect
public class CaculateAspect {
@Pointcut("execution(* com.jw.springframework.g_aop.Caculate.*(..))")
public void pointCut() {
}
@Before(value = "pointCut()")
public void methodBefore(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
System.out.println("执行目标方法[" + methodName + "]的前置通知, 入参: " + Arrays.asList(joinPoint.getArgs()));
}
@After(value = "pointCut()")
public void methodAfter(JoinPoint joinPoint){
String methodName = joinPoint.getSignature().getName();
System.out.println("执行目标方法[" + methodName + "]的后置通知, 入参: " + Arrays.asList(joinPoint.getArgs()));
}
// 引入
/*@DeclareParents(value = "com.jw.springframework.g_aop.Caculate", // 需要动态增强的类
defaultImpl = ProgramCaculateImpl.class) // 引入接口的默认实现
public ProgramCaculate programCaculate; // 引入的接口*/
}
需要被增强的类, 以及切点方法jointPoint
@Component
public class Caculate {
public int add(int a, int b){
System.out.println("执行add方法, 本切点具有前置和后置通知");
return a + b;
}
}
运行结果:
执行目标方法[add]的前置通知, 入参: [1, 2]
执行add方法, 本切点具有前置和后置通知
执行目标方法[add]的后置通知, 入参: [1, 2]
3
要使用AOP首先需要在某个能被扫描的类上加上@EnableAspectJAutoProxy注解, 保证开启了AOP功能
然后写一个切面类, 使用@Aspect注解标注, 再在本切面类上写一个@PointCut("切点表达式")注解的方法, 保证明确切点目标
再在切面类中写通知, 使用@Around, @Before, @After等等之类的注解表示这是一个什么样的通知
最终都会被spring解析, 对要增强的切点方法所在的对象进行动态代理, 把所有的通知, 每个通知解析成为一个Advisor对象, 在最后转换成interceptor, 最终通过责任链的方式进行依次调用, 实现对方法的增强
首先看看@EnableAspectJAutoProxy注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
/*xxx: 这个是允许Aspectj自动代理的注解*/
/*xxx: 在springboot中,默认是会配置这个注解,并且默认用的是 cglib的代理*/
/*xxx: 与之想对的是,spring默认用的是 jdk接口代理*/
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
/**
* Indicate whether subclass-based (CGLIB) proxies are to be created as opposed
* to standard Java interface-based proxies. The default is {@code false}.
*/
boolean proxyTargetClass() default false;
/**
* Indicate that the proxy should be exposed by the AOP framework as a {@code ThreadLocal}
* for retrieval via the {@link org.springframework.aop.framework.AopContext} class.
* Off by default, i.e. no guarantees that {@code AopContext} access will work.
* @since 4.3.1
*/
boolean exposeProxy() default false;
}
其中proxyTargetClass属性代表可以选择强制使用cglib代理, 后续会说明如何作用的
exposeProxy属性表示是否暴露当前代理对象到ThreadLocal中去, 我们知道, 如果使用jdk动态代理, 在增强方法中内嵌再调用一个增强方法, 默认是不会执行内嵌方法的增强的, 这是因为jdk动态代理是通过反射调用, 所以spring做了一种解决方案, 在AopContext中有一个ThreadLocal变量, 如下代码所示
public final class AopContext {
/**
* ThreadLocal holder for AOP proxy associated with this thread.
* Will contain {@code null} unless the "exposePro