Spring aop使用非常广泛就不说了。除了常见的使用@Aspect注解作为切面配合自定义注解作为切点实现AOP拦截外,还可以使用本文介绍的Advisor实现AOP。
本文介绍基于Spring-aop依赖包下的Advisor接口实现AOP的方式。首先概述一下,这种实现方式主要是创建Advisor接口实例,并指定Advice和Pointcut,其中Advice接口实例扮演Advice通知的角色,Pointcut接口实例扮演切入点的角色,然后把Advisor实例注入到Spring中就可以实现AOP了。
PointcutAdvisor接口是Advisor的子接口,Advisor是Spring AOP的顶层抽象,用来管理Advice和Pointcut,所以毫无疑问PointcutAdvisor接口也是用来管理Advice和Pointcut的。
Pointcut接口有两个接口方法,分别用于加载ClassFilter和MethodMatcher接口实例,并通过这两个实例实现切入点的逻辑功能。
- public interface Pointcut {
- Pointcut TRUE = TruePointcut.INSTANCE;
- //加载ClassFilter实例
- ClassFilter getClassFilter();
- //加载MethodMatcher实例
- MethodMatcher getMethodMatcher();
- }
ClassFilter的matches方法定义判断某个类是否需要被纳入切面
- public interface ClassFilter {
- boolean matches(Class> clazz);
-
- ClassFilter TRUE = TrueClassFilter.INSTANCE;
- }
MethodMatcher的matches方法则是定义判断某个方法是否需要被纳入切面。
- public interface MethodMatcher {
- boolean isRuntime();
-
- //静态检查给定方法是否匹配
- boolean matches(Method method, Class> targetClass);
-
- //检查此方法是否存在运行时(动态)匹配
- boolean matches(Method method, Class> targetClass, Object... args);
-
- MethodMatcher TRUE = TrueMethodMatcher.INSTANCE;
- }
这个接口spring-aop依赖下org.aopalliance.intercept.Interceptor接口的子接口,而Interceptor接口又是Advice接口的子接口,所以MethodInterceptor接口也是Advice接口的子接口。(有点啰嗦)
MethodInterceptor接口主要提供一个invoke方法,用于定义通知逻辑,即对切点执行的逻辑代码。
- public interface MethodInterceptor extends Interceptor {
-
- Object invoke(MethodInvocation invocation) throws Throwable;
-
- }
上面把各个接口都介绍完了。现在整理一下流程做一下总结:
- 使用PointcutAdvisor接口实例(切面)把Pointcut接口实例(切点)和Advice接口实例(通知逻辑)整合起来并注入到Spring中,这样就能项目启动过程中实现AOP。
- 项目启动时会调用PointcutAdvisor接口的getPointcut和getAdvice方法,得到预先定义的切面逻辑实例(Pointcut接口实例)和织入方法逻辑实例(MethodInterceptor接口实例),得到实例后立即执行Pointcut接口实例中ClassFilter和MethodMatcher的match方法判断那些类或方法需要被纳入切面范围,实现动态构建切点信息。
- MethodInterceptor接口(Advice的子接口)的invoke方法则是通知逻辑,只需要被PointcutAdvisor接口加载即可,通知逻辑会在代码运行过程中对切点拦截后执行处理。
上面第2点流程代码体现在org.springframework.aop.support.AopUtils#canApply 方法中
- public static boolean canApply(Pointcut pc, Class> targetClass, boolean hasIntroductions) {
- Assert.notNull(pc, "Pointcut must not be null");
- if (!pc.getClassFilter().matches(targetClass)) {
- return false;
- }
-
- MethodMatcher methodMatcher = pc.getMethodMatcher();
- if (methodMatcher == MethodMatcher.TRUE) {
- // No need to iterate the methods if we're matching any method anyway...
- return true;
- }
-
- IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
- if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
- introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
- }
-
- Set
> classes = new LinkedHashSet>(ClassUtils.getAllInterfacesForClassAsSet(targetClass)); - classes.add(targetClass);
- for (Class> clazz : classes) {
- Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
- for (Method method : methods) {
- if ((introductionAwareMethodMatcher != null &&
- introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions)) ||
- methodMatcher.matches(method, targetClass)) {
- return true;
- }
- }
- }
-
- return false;
- }
Spring中给PointcutAdvisor接口提供一个一个默认的实现类DefaultPointcutAdvisor和Pointcut接口默认实现类AspectJExpressionPointcut,如果不想自己在定义切面和切点实现类可以直接使用默认实现。
- @Configuration
- public class PointcutAdvisorConfig {
-
- public static final String traceExecution = "execution(* cn.demo.service..*.*(..))";
-
- @Bean
- public DefaultPointcutAdvisor defaultPointcutAdvisor1() {
- //使用默认的切面advisor实例
- DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor();
- //使用默认的切点实例
- AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
- pointcut.setExpression(traceExecution);
- advisor.setPointcut(pointcut);
- //配置自定义的通知实例
- MyInterceptor interceptor = new MyInterceptor();
- advisor.setAdvice(interceptor);
- return advisor;
- }
- }
- //只需额外自定义通知实现类即可
- public class MyInterceptor implements MethodInterceptor {
-
- @Override
- public Object invoke(MethodInvocation invocation) throws Throwable {
- System.out.println(invocation.getMethod() + "==方法执行前==");
- Object proceed = invocation.proceed();
- System.out.println(invocation.getArguments() + "--方法执行后--");
- return proceed;
- }
-
- }
- //定义切面类
- public class MapperMethodAdviceBean implements PointcutAdvisor, EnvironmentAware, ApplicationContextAware {
- private Environment environment;
- private ApplicationContext applicationContext;
-
- public MapperMethodAdviceBean() {
- }
-
- public void setEnvironment(Environment environment) {
- this.environment = environment;
- }
-
- public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
- this.applicationContext = applicationContext;
- }
-
- public Pointcut getPointcut() {
- return new MapperMethodPointCut();
- }
-
- public Advice getAdvice() {
- return new MapperMethodAdvise(this.environment, this.applicationContext);
- }
-
- public boolean isPerInstance() {
- return true;
- }
- }
-
- //定义切点类
- public class MapperMethodPointCut implements Pointcut {
- public MapperMethodPointCut() {
- }
-
- public ClassFilter getClassFilter() {
- return new MyClassFilter();
- }
-
- public MethodMatcher getMethodMatcher() {
- return new MyMethodMatcher();
- }
-
-
- public boolean isRuntime() {
- return false;
- }
-
- //定义ClassFilter接口实例类并定义切点判断逻辑
- class MyClassFilter implements ClassFilter{
- @Override
- public boolean matches(Class> clazz) {
- // 如果mapper包下的包含Mapper注解就返回true 作为切点
- if (clazz != null && StringUtils.contains(clazz.getName(), "cn.demo.mapper")) {
- return aClass.getSuperclass().getName().equals(Proxy.class.getName()) && aClass.getInterfaces()[0].isAnnotationPresent(Mapper.class);
- }
- return false;
- }
- }
- //定义MethodMatcher接口实例类并定义切点判断逻辑
- class MyMethodMatcher implements MethodMatcher{
-
- //判断方法是否匹配
- @Override
- public boolean matches(Method method, Class> targetClass, Object... args) {
- return true;
- }
-
- //判断方法是否匹配
- @Override
- public boolean matches(Method method, Class> targetClass) {
- return true;
- }
-
- @Override
- public boolean isRuntime() {
- return false;
- }
- }
- }
-
- //定义通知逻辑
- public class MapperMethodAdvise implements MethodInterceptor {
- private Environment environment;
- private ApplicationContext applicationContext;
-
- public MapperMethodAdvise(Environment environment, ApplicationContext applicationContext) {
- this.environment = environment;
- this.applicationContext = applicationContext;
- }
-
- public Object invoke(MethodInvocation methodInvocation) throws Throwable {
- return methodInvocation.proceed();
- }
-
- }
如果切面织入即PointcutAdvisor接口类也自己定义,则需要借助BeanDefinitionRegistryPostProcessor扩展接口把切面实例注入到Spring中才生效。
- //定义BeanDefinitionRegistryPostProcessor注册PointcutAdvisor实例的BD
- public class MapperMethodPropertyProcessor implements PriorityOrdered, BeanDefinitionRegistryPostProcessor {
- public MapperMethodPropertyProcessor() {
- }
-
- public int getOrder() {
- return 0;
- }
-
- public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
- BeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(MapperMethodAdviceBean.class).getBeanDefinition();
- beanDefinitionRegistry.registerBeanDefinition(MapperMethodAdviceBean.class.getName(), beanDefinition);
- }
-
- public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
- }
- }
-
- //配置自定义的BeanDefinitionRegistryPostProcessor注册到Spring容器
- @Configuration
- public class MapperMethodProxyAutoConfiguration {
- public MapperMethodProxyAutoConfiguration() {
- }
-
- @Bean
- public MapperMethodPropertyProcessor mapperMethodPropertyProcessor() {
- return new MapperMethodPropertyProcessor();
- }
- }