网站建设厦门,网页空间是什么意思,网站设计模板是什么,wordpress股票文章目录系列文档索引四、Spring AOP的使用入门1、激活AspectJ模块#xff08;1#xff09;注解激活#xff08;2#xff09;XML激活2、创建 AspectJ 代理#xff08;了解#xff09;#xff08;1#xff09;编程方式创建 AspectJ 代理实例#xff08;2#xff09;XM…
文章目录系列文档索引四、Spring AOP的使用入门1、激活AspectJ模块1注解激活2XML激活2、创建 AspectJ 代理了解1编程方式创建 AspectJ 代理实例2XML 配置创建 AOP 代理3标准代理工厂 API3、Pointcut 使用1Pointcut 指令与表达式2XML 配置 Pointcut3API 实现 Pointcut4、拦截动作1注解方式实现2XML配置方式实现3API方式实现4同一个Before执行顺序未完待续参考资料系列文档索引
SpringAOP从入门到源码分析大全学好AOP这一篇就够了一 SpringAOP从入门到源码分析大全学好AOP这一篇就够了二 SpringAOP从入门到源码分析大全学好AOP这一篇就够了三 SpringAOP从入门到源码分析大全学好AOP这一篇就够了四
四、Spring AOP的使用入门
1、激活AspectJ模块
激活AspectJ模块分两种方式一种是使用注解方式一种使用xml方式。
• 注解激活 - EnableAspectJAutoProxy • XML 配置 - aop:aspectj-autoproxy/
1注解激活
import org.aspectj.lang.annotation.Aspect;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;Aspect // 声明为 Aspect 切面
Configuration // Configuration class
EnableAspectJAutoProxy // 激活 Aspect 注解自动代理
public class AspectJAnnotationDemo {public static void main(String[] args) {AnnotationConfigApplicationContext context new AnnotationConfigApplicationContext();context.register(AspectJAnnotationDemo.class);context.refresh();AspectJAnnotationDemo aspectJAnnotationDemo context.getBean(AspectJAnnotationDemo.class);System.out.println(aspectJAnnotationDemo.getClass());context.close();}
}以上是使用注解激活的实例使用EnableAspectJAutoProxy即可激活Aspect注解自动代理。
该AspectJAnnotationDemo类使用Configuration标注代表是一个配置类Spring中的配置类都会被代理默认是使用CGLIB代理。
Aspect表示该类是一个切面类。
2XML激活
在xml文件中使用该标签即可激活Aspect自动代理
aop:aspectj-autoproxy/该标签与注解的EnableAspectJAutoProxy效果相同。
2、创建 AspectJ 代理了解
1编程方式创建 AspectJ 代理实例
实现类 org.springframework.aop.aspectj.annotation.AspectJProxyFactory
import org.springframework.aop.AfterReturningAdvice;
import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.aop.aspectj.annotation.AspectJProxyFactory;
import org.springframework.aop.framework.AopContext;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;public class AspectJAnnotationUsingAPIDemo {public static void main(String[] args) {// 通过创建一个 HashMap 缓存作为被代理对象MapString, Object cache new HashMap();// 创建 Proxy 工厂(AspectJ)AspectJProxyFactory proxyFactory new AspectJProxyFactory(cache);// 增加 Aspect 配置类暂时不需要
// proxyFactory.addAspect(AspectConfiguration.class);// 设置暴露代理对象到 AopContextproxyFactory.setExposeProxy(true);proxyFactory.addAdvice(new MethodBeforeAdvice() {Overridepublic void before(Method method, Object[] args, Object target) throws Throwable {if (put.equals(method.getName()) args.length 2) {Object proxy AopContext.currentProxy();System.out.printf([MethodBeforeAdvice] 当前存放是 Key: %s , Value : %s 代理对象%s\n, args[0], args[1], proxy);}}});// 添加 AfterReturningAdviceproxyFactory.addAdvice(new AfterReturningAdvice() {Overridepublic void afterReturning(Object returnValue, Method method, Object[] args, Object target)throws Throwable {if (put.equals(method.getName()) args.length 2) {System.out.printf([AfterReturningAdvice] 当前存放是 Key: %s , 新存放的 Value : %s , 之前关联的 Value : %s\n ,args[0], // keyargs[1], // new valuereturnValue // old value);}}});// 通过代理对象存储数据MapString, Object proxy proxyFactory.getProxy();proxy.put(1, A);proxy.put(1, B);System.out.println(cache.get(1));}
}2XML 配置创建 AOP 代理
aop:aspectj-autoproxy/bean idechoService classcom.demo.DefaultEchoService/bean!--拦截器--
bean idechoServiceMethodInterceptorclasscom.demo.interceptor.EchoServiceMethodInterceptor/bean idechoServiceProxyFactoryBean classorg.springframework.aop.framework.ProxyFactoryBeanproperty nametargetName valueechoService/ !--指定targetName为需要代理的bean的Id--property nameinterceptorNames !--指定拦截器--valueechoServiceMethodInterceptor/value/property
/beanimport org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import java.lang.reflect.Method;public class EchoServiceMethodInterceptor implements MethodInterceptor {Overridepublic Object invoke(MethodInvocation invocation) throws Throwable {Method method invocation.getMethod();System.out.println(拦截 EchoService 的方法 method);return invocation.proceed();}
}
import org.aspectj.lang.annotation.Aspect;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ClassPathXmlApplicationContext;Aspect // 声明为 Aspect 切面
Configuration // Configuration class
public class ProxyFactoryBeanDemo {public static void main(String[] args) {ClassPathXmlApplicationContext context new ClassPathXmlApplicationContext(classpath:/META-INF/spring-aop-context.xml);EchoService echoService context.getBean(echoServiceProxyFactoryBean, EchoService.class);System.out.println(echoService.echo(Hello,World));System.out.println(echoService.getClass());context.close();}
}我们发现这种方式与编程的方式创建代理是差不多的只不过是对象的创建交给Spring来处理了。
3标准代理工厂 API
实现类 - org.springframework.aop.framework.ProxyFactory
上面XML配置的方式创建ProxyFactoryBean更多用于Spring中的应用而ProxyFactory更偏底层。
import org.springframework.aop.framework.ProxyFactory;/*** ProxyFactory使用示例*/
public class ProxyFactoryDemo {public static void main(String[] args) {DefaultEchoService defaultEchoService new DefaultEchoService();// 注入目标对象被代理ProxyFactory proxyFactory new ProxyFactory(defaultEchoService);//proxyFactory.setTargetClass(DefaultEchoService.class);// 添加 Advice 实现 MethodInterceptor Interceptor AdviceproxyFactory.addAdvice(new EchoServiceMethodInterceptor());// 获取代理对象EchoService echoService (EchoService) proxyFactory.getProxy();System.out.println(echoService.echo(Hello,World));}
}import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import java.lang.reflect.Method;public class EchoServiceMethodInterceptor implements MethodInterceptor {Overridepublic Object invoke(MethodInvocation invocation) throws Throwable {Method method invocation.getMethod();System.out.println(拦截 EchoService 的方法 method);return invocation.proceed();}
}3、Pointcut 使用
Spring中的Pointcut只支持方法级别的定义也就是说只支持Bean的方法拦截。
Pointcut 只是一个筛选并没有具体的动作。 Advice才是具体的动作一个Pointcut 可以对应多个Advice。
1Pointcut 指令与表达式
Spring AOP 之 aspect表达式详解
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;/*** Pointcut 示例*/
Configuration // Configuration class
EnableAspectJAutoProxy // 激活 Aspect 注解自动代理
public class AspectJAnnotatedPointcutDemo {public static void main(String[] args) {AnnotationConfigApplicationContext context new AnnotationConfigApplicationContext();context.register(AspectJAnnotatedPointcutDemo.class,AspectConfiguration.class);context.refresh();AspectJAnnotatedPointcutDemo aspectJAnnotationDemo context.getBean(AspectJAnnotatedPointcutDemo.class);aspectJAnnotationDemo.execute();context.close();}public void execute() {System.out.println(execute()...);}
}/*** Aspect 配置类*/
Aspect
public class AspectConfiguration {Pointcut(execution(public * *(..))) // 匹配 Join Pointprivate void anyPublicMethod() { // 方法名即 Pointcut 名System.out.println(Pointcut at any public method.); // 方法通常设置为空的不会有具体的动作}Before(anyPublicMethod()) // Join Point 拦截动作public void beforeAnyPublicMethod() {System.out.println(Before any public method.);}}Pointcut定义在切面类的私有方法上该方法没有任何的动作只是筛选要切入的方法。该方法名即为Pointcut名。
2XML 配置 Pointcut
!--定义配置类--
bean idaspectXmlConfig classcom.demo.AspectXmlConfig/aop:configaop:aspect idAspectXmlConfig refaspectXmlConfig!--引用配置类--aop:pointcut idanyPublicMethod expressionexecution(public * *(..))/!--Pointcut--aop:before methodbeforeAnyPublicMethod pointcut-refanyPublicMethod/!--配置类的方法--/aop:aspect
/aop:configpublic class AspectXmlConfig {public void beforeAnyPublicMethod() {System.out.println(Before any public method.);}
}3API 实现 Pointcut
核心 API - org.springframework.aop.Pointcut • org.springframework.aop.ClassFilter • org.springframework.aop.MethodMatcher
适配实现 - DefaultPointcutAdvisor
public static void main(String[] args) {EchoServicePointcut echoServicePointcut new EchoServicePointcut(echo, EchoService.class);// 将 Pointcut 适配成 AdvisorDefaultPointcutAdvisor advisor new DefaultPointcutAdvisor(echoServicePointcut, new EchoServiceMethodInterceptor());DefaultEchoService defaultEchoService new DefaultEchoService();ProxyFactory proxyFactory new ProxyFactory(defaultEchoService);// 添加 AdvisorproxyFactory.addAdvisor(advisor);// 获取代理对象EchoService echoService (EchoService) proxyFactory.getProxy();System.out.println(echoService.echo(Hello,World));
}public class EchoServicePointcut extends StaticMethodMatcherPointcut {private String methodName;private Class targetClass;public EchoServicePointcut(String methodName, Class targetClass) {this.methodName methodName;this.targetClass targetClass;}Overridepublic boolean matches(Method method, Class? targetClass) {return Objects.equals(methodName, method.getName()) this.targetClass.isAssignableFrom(targetClass);}public String getMethodName() {return methodName;}public void setMethodName(String methodName) {this.methodName methodName;}public Class getTargetClass() {return targetClass;}public void setTargetClass(Class targetClass) {this.targetClass targetClass;}
}
public class EchoServiceMethodInterceptor implements MethodInterceptor {Overridepublic Object invoke(MethodInvocation invocation) throws Throwable {Method method invocation.getMethod();System.out.println(拦截 EchoService 的方法 method);return invocation.proceed();}
}
4、拦截动作
Around环绕动作。
Before前置动作。
After后置动作 • 方法返回后AfterReturning • 异常发生后AfterThrowing • finally 执行After
1注解方式实现
Aspect
Order
public class AspectConfiguration {Pointcut(execution(public * *(..))) // 匹配 Join Pointprivate void anyPublicMethod() { // 方法名即 Pointcut 名System.out.println(Pointcut at any public method.);}Around(anyPublicMethod()) // Join Point 拦截动作public Object aroundAnyPublicMethod(ProceedingJoinPoint pjp) throws Throwable {System.out.println(Around any public method.);return pjp.proceed();}Before(anyPublicMethod()) // Join Point 拦截动作public void beforeAnyPublicMethod() {Random random new Random();if (random.nextBoolean()) {throw new RuntimeException(For Purpose.);}System.out.println(Before any public method.);}After(anyPublicMethod())public void finalizeAnyPublicMethod() {System.out.println(After any public method.);}AfterReturning(anyPublicMethod())// AspectJAfterReturningAdvice is AfterReturningAdvice// 一个 AfterReturningAdviceInterceptor 关联一个 AfterReturningAdvice// Spring 封装 AfterReturningAdvice - AfterReturningAdviceInterceptor// AfterReturningAdviceInterceptor is MethodInterceptor// AfterReturningAdviceInterceptor// - AspectJAfterReturningAdvice// - AbstractAspectJAdvice#invokeAdviceMethodWithGivenArgspublic void afterAnyPublicMethod() {System.out.println(AfterReturning any public method.);}AfterThrowing(anyPublicMethod())public void afterThrowingAnyPublicMethod() {System.out.println(AfterThrowing any public method);}public String toString() {return AspectConfiguration;}private int getValue() {return 0;}
}
2XML配置方式实现
aop:config!-- aop:pointcut idallPointcut expressionexecution(* * *(..))/--aop:aspect idAspectXmlConfig refaspectXmlConfigaop:pointcut idanyPublicMethod expressionexecution(public * *(..))/aop:around methodaroundAnyPublicMethod pointcut-refanyPublicMethod/aop:around methodaroundAnyPublicMethod pointcutexecution(public * *(..))/aop:before methodbeforeAnyPublicMethod pointcut-refanyPublicMethod/aop:before methodbeforeAnyPublicMethod pointcutexecution(public * *(..))/aop:after methodfinalizeAnyPublicMethod pointcut-refanyPublicMethod/aop:after-returning methodafterAnyPublicMethod pointcut-refanyPublicMethod/aop:after-throwing methodafterThrowingAnyPublicMethod pointcut-refanyPublicMethod//aop:aspect
/aop:configpublic class AspectXmlConfig {public Object aroundAnyPublicMethod(ProceedingJoinPoint pjp) throws Throwable {Random random new Random();if (random.nextBoolean()) {throw new RuntimeException(For Purpose from XML configuration.);}System.out.println(Around any public method : pjp.getSignature());return pjp.proceed();}public void beforeAnyPublicMethod() {System.out.println(Before any public method.);}public void finalizeAnyPublicMethod() {System.out.println(After any public method.);}public void afterAnyPublicMethod() {System.out.println(AfterReturning any public method.);}public void afterThrowingAnyPublicMethod() {System.out.println(AfterThrowing any public method.);}
}3API方式实现
为什么 Spring AOP 不需要设计 Around Advice • AspectJ Around 与 org.aspectj.lang.ProceedingJoinPoint 配合执行被代理方法 • ProceedingJoinPoint#proceed() 方法类似于 Java Method#invoke(Object,Object…) • Spring AOP 底层 API ProxyFactory 可通过 addAdvice 方法与 Advice 实现关联 • 接口 Advice 是 Interceptor 的父亲接口而接口 MethodInterceptor 又扩展了 Interceptor • MethodInterceptor 的invoke 方法参数 MethodInvocation 与 ProceedingJoinPoint 类似
API 实现 Before Advice
核心接口 - org.springframework.aop.BeforeAdvice
类型标记接口与 org.aopalliance.aop.Advice 类似
方法 JoinPoint 扩展 - org.springframework.aop.MethodBeforeAdvice
接受对象 - org.springframework.aop.framework.AdvisedSupport • 基础实现类 - org.springframework.aop.framework.ProxyCreatorSupport • 常见实现类org.springframework.aop.framework.ProxyFactoryorg.springframework.aop.framework.ProxyFactoryBeanorg.springframework.aop.aspectj.annotation.AspectJProxyFactory
API 实现三种 After Advice
核心接口 - org.springframework.aop.AfterAdvice
类型标记接口与 org.aopalliance.aop.Advice 类似
扩展 • org.springframework.aop.AfterReturningAdvice • org.springframework.aop.ThrowsAdvice
接受对象 - org.springframework.aop.framework.AdvisedSupport • 基础实现类 - org.springframework.aop.framework.ProxyCreatorSupport • 常见实现类org.springframework.aop.framework.ProxyFactoryorg.springframework.aop.framework.ProxyFactoryBeanorg.springframework.aop.aspectj.annotation.AspectJProxyFactory
// 通过创建一个 HashMap 缓存作为被代理对象
MapString, Object cache new HashMap();
// 创建 Proxy 工厂(AspectJ)
AspectJProxyFactory proxyFactory new AspectJProxyFactory(cache);
// 增加 Aspect 配置类此处不需要
// proxyFactory.addAspect(AspectConfiguration.class);
// 设置暴露代理对象到 AopContext
proxyFactory.setExposeProxy(true);
proxyFactory.addAdvice(new MethodBeforeAdvice() {Overridepublic void before(Method method, Object[] args, Object target) throws Throwable {if (put.equals(method.getName()) args.length 2) {Object proxy AopContext.currentProxy();System.out.printf([MethodBeforeAdvice] 当前存放是 Key: %s , Value : %s 代理对象%s\n, args[0], args[1], proxy);}}
});// 添加 AfterReturningAdvice
proxyFactory.addAdvice(new AfterReturningAdvice() {Overridepublic void afterReturning(Object returnValue, Method method, Object[] args, Object target)throws Throwable {if (put.equals(method.getName()) args.length 2) {System.out.printf([AfterReturningAdvice] 当前存放是 Key: %s , 新存放的 Value : %s , 之前关联的 Value : %s\n ,args[0], // keyargs[1], // new valuereturnValue // old value);}}
});// 通过代理对象存储数据
MapString, Object proxy proxyFactory.getProxy();
proxy.put(1, A);
proxy.put(1, B);
System.out.println(cache.get(1));4同一个Before执行顺序
注解驱动使用Order注解标注切面类同一类中的顺序无法保证。
XML驱动按照先后顺序执行。
未完待续
参考资料
极客时间《小马哥讲 Spring AOP 编程思想》