zoukankan      html  css  js  c++  java
  • Spring 使用AspectJ的三种方式

    Spring 使用AspectJ 的三种方式

    一,使用JavaConfig

    二,使用注解隐式配置

    三,使用XML 配置

    背景知识:

    注意 使用AspectJ 的 时候 要导入相应的Jar 包

    嗯 昨天还碰到了这样的问题:

    Caused by: java.lang.IllegalArgumentException: error at ::0 can't find referenced pointcut ArithmeticPointCut

     1 java.lang.IllegalStateException: Failed to load ApplicationContext
     2     at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:124)
     3     at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:83)
     4     at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:117)
     5     at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:83)
     6     at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:230)
     7     at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:228)
     8     at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:287)
     9     at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    10     at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:289)
    11     at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:247)
    12     at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:94)
    13     at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    14     at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    15     at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    16     at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    17     at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    18     at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    19     at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
    20     at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    21     at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191)
    22     at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
    23     at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    24     at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
    25     at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:678)
    26     at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
    27     at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
    28 Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.context.event.internalEventListenerProcessor': Initialization of bean failed; nested exception is java.lang.IllegalArgumentException: error at ::0 can't find referenced pointcut ArithmeticPointCut
    29     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:564)
    30     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483)
    31     at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
    32     at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
    33     at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
    34     at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
    35     at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:761)
    36     at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:867)
    37     at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:543)
    38     at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:128)
    39     at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:60)
    40     at org.springframework.test.context.support.AbstractDelegatingSmartContextLoader.delegateLoading(AbstractDelegatingSmartContextLoader.java:108)
    41     at org.springframework.test.context.support.AbstractDelegatingSmartContextLoader.loadContext(AbstractDelegatingSmartContextLoader.java:251)
    42     at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:98)
    43     at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:116)
    44     ... 25 more
    45 Caused by: java.lang.IllegalArgumentException: error at ::0 can't find referenced pointcut ArithmeticPointCut
    46     at org.aspectj.weaver.tools.PointcutParser.parsePointcutExpression(PointcutParser.java:317)
    47     at org.springframework.aop.aspectj.AspectJExpressionPointcut.buildPointcutExpression(AspectJExpressionPointcut.java:217)
    48     at org.springframework.aop.aspectj.AspectJExpressionPointcut.checkReadyToMatch(AspectJExpressionPointcut.java:190)
    49     at org.springframework.aop.aspectj.AspectJExpressionPointcut.getClassFilter(AspectJExpressionPointcut.java:169)
    50     at org.springframework.aop.support.AopUtils.canApply(AopUtils.java:220)
    51     at org.springframework.aop.support.AopUtils.canApply(AopUtils.java:279)
    52     at org.springframework.aop.support.AopUtils.findAdvisorsThatCanApply(AopUtils.java:311)
    53     at org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.findAdvisorsThatCanApply(AbstractAdvisorAutoProxyCreator.java:119)
    54     at org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.findEligibleAdvisors(AbstractAdvisorAutoProxyCreator.java:89)
    55     at org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.getAdvicesAndAdvisorsForBean(AbstractAdvisorAutoProxyCreator.java:70)
    56     at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.wrapIfNecessary(AbstractAutoProxyCreator.java:346)
    57     at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.postProcessAfterInitialization(AbstractAutoProxyCreator.java:298)
    58     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsAfterInitialization(AbstractAutowireCapableBeanFactory.java:423)
    59     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1633)
    60     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:555)
    61     ... 39 more
    Error

    更换了Jar 包  从 1.5 --> 换到了 1.8.10 就好了  注意  aspectj 和asectjweaver 要版本对应

    JavaConfig 

    类的结构 如 下图 所示 

    ① Java Config 

    代码如下:  其中要注意@EnableAspectJAutoProxy(proxyTargetClass=true)   默认值为 false  只有开启proxyTargetClass 才会实现AspectJ 的切片功能

     1 package com.myth.spring.aop.config;
     2 
     3 import org.springframework.context.annotation.ComponentScan;
     4 import org.springframework.context.annotation.EnableAspectJAutoProxy;
     5 import org.springframework.stereotype.Component;
     6 
     7 @Component
     8 @EnableAspectJAutoProxy(proxyTargetClass=true)
     9 @ComponentScan(basePackages="com.myth.spring.aop")
    10 public class ArithmeticCaculatorConfig {
    11 
    12 }
    ArithmeticCaculatorConfig

    ② Service 类下面就是最基本的 实现类 代码如下:

    注意每个类前 要加上@Component的标签

    1 package com.myth.spring.aop.service;
    2 
    3 public interface IArithmeticCaculator {
    4     public int add(int a ,int b);
    5     public int sub(int a ,int b);
    6     public int mul(int a ,int b);
    7     public int div(int a ,int b);
    8 }
    IArithmeticCaculator
     1 package com.myth.spring.aop.service.impl;
     2 
     3 import org.springframework.stereotype.Component;
     4 
     5 import com.myth.spring.aop.service.IArithmeticCaculator;
     6 import com.myth.springAOP.exception.NotZeroException;
     7 @Component
     8 public class ArithmeticCaculatorImpl implements IArithmeticCaculator{
     9 
    10     @Override
    11     public int add(int a, int b) {
    12         System.out.println(a + b);
    13         return a + b;
    14     }
    15 
    16     @Override
    17     public int sub(int a, int b) {
    18         return a - b;
    19     }
    20 
    21     @Override
    22     public int mul(int a, int b) {
    23         return a * b;
    24     }
    25 
    26     @Override
    27     public int div(int a, int b) {
    28         if (b == 0) {
    29             throw new NotZeroException("除数不能为空");
    30         }
    31         return a / b;
    32     }
    33 }
    ArithmeticCaculatorImpl

    ③ Aspect 类

    这个类中 需要注意的点就比较多了

    我在其中只写了  @Before , @After 和 @AfterReturning 

    1.定义为@Aspect

    2.定义@Pointcut  根据这个切点来描写方法

    3.写其中的@Before 或者其他Aspect 方法

    当我们调用JoinPoint 时  要 joinpoint  要选择org.aspectj.lang.JoinPoint

     1 package com.myth.spring.aop.service.aspect;
     2 
     3 import java.util.Arrays;
     4 
     5 import org.aspectj.lang.JoinPoint;
     6 import org.aspectj.lang.annotation.AfterReturning;
     7 import org.aspectj.lang.annotation.Aspect;
     8 import org.aspectj.lang.annotation.Before;
     9 import org.aspectj.lang.annotation.Pointcut;
    10 import org.springframework.stereotype.Component;
    11 
    12 @Component
    13 @Aspect
    14 /**
    15  * 要在Config中配置@EnableAspectJAutoProxy(proxyTargetClass=true) 默认为false
    16  * joinpoint  要选择org.aspectj.lang.JoinPoint
    17  *
    18  */
    19 public class LoggingAspect {
    20     @Pointcut("execution(* com.myth.spring.aop.service.impl.ArithmeticCaculatorImpl.*(int , int ))")
    21     public void ArithmeticPointCut() {}
    22     
    23     @Before("ArithmeticPointCut()")
    24     public void before(JoinPoint joinpoint) {
    25         String method = joinpoint.getSignature().getName();
    26         System.out.println("The method "+method+" begins with "+Arrays.asList(joinpoint.getArgs()));
    27     }
    28     
    29 /*    @After(value= "ArithmeticPointCut()")
    30     public void After(JoinPoint joinpoint) {
    31         String method = joinpoint.getSignature().getName();
    32         System.out.println("The method "+method+" ends with ");
    33     }*/
    34     
    35     @AfterReturning(value="ArithmeticPointCut()", returning = "result")
    36     public void afterReturn(JoinPoint joinPoint ,Object result) {
    37         String method = joinPoint.getSignature().getName();
    38         System.out.println("The method "+method+" ends with " + result);
    39     }
    40 }
    LoggingAspect

     ④ Junit 类

    关于Junit 类 可以关注  我的这篇帖子

    使用Spring的隐式注解和装配以及使用SpringTest框架

    http://www.cnblogs.com/mythdoraemon/p/7533553.html

    代码如下:

     1 package com.myth.spring.aop.test;
     2 
     3 import static org.junit.Assert.*;
     4 
     5 import org.junit.Test;
     6 import org.junit.runner.RunWith;
     7 import org.springframework.beans.factory.annotation.Autowired;
     8 import org.springframework.test.context.ContextConfiguration;
     9 import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    10 
    11 import com.myth.spring.aop.config.ArithmeticCaculatorConfig;
    12 import com.myth.spring.aop.service.IArithmeticCaculator;
    13 @RunWith(SpringJUnit4ClassRunner.class)
    14 @ContextConfiguration(classes=ArithmeticCaculatorConfig.class)
    15 public class TestAspect {
    16 
    17     @Autowired
    18     private IArithmeticCaculator iArithmeticCaculator;
    19     
    20     @Test
    21     public void test() {
    22         iArithmeticCaculator.add(1, 2);
    23     }
    24 
    25 }
    TestAspect 

    注解注入

     注解注入大部分与JavaConfig 很像 , 其实就是把Java Config 的内容去不都写到了XML 中 罢了

    结构如下:

    我们跟上面的结构对应起来

    ① Java Config  这里应该是容器 applicationContext.xml

     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <beans xmlns="http://www.springframework.org/schema/beans"
     3     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     4     xmlns:aop="http://www.springframework.org/schema/aop"
     5     xmlns:context="http://www.springframework.org/schema/context"
     6     xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
     7         http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
     8         http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
     9 <!-- 添加自动扫描机制 -->
    10     <context:component-scan base-package="com.myth.spring.aop.annotion"></context:component-scan>
    11     
    12     
    13 <!-- 添加切面机制 -->
    14     <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
    15 
    16 </beans>
    applicationContext.xml

    ② Service 类 与上面的代码一样  就不重复写了

    ③ Aspect 类 也与 前面的一样 这回我写的是Around 方法

    Around 其实包括了其他4种切面方式

     1 /**
     2      * 对于环绕通知来说, 连接点的参数类型必须是 ProceedingJoinPoint . 它是 JoinPoint 的子接口, 允许控制何时执行,
     3      * 是否执行连接点.
     4      * 环绕通知必须有返回值,返回值为proceedingJoinPoint.proceed() 的结果
     5      * @param proceedingJoinPoint
     6      */
     7     @Around(value = "ArithmeticPointCut()")
     8     public Object Around(ProceedingJoinPoint proceedingJoinPoint) {
     9         String method = proceedingJoinPoint.getSignature().getName();
    10         Object result = null;
    11         try {
    12             //相当于前置通知
    13             System.out.println("The method " + method + " begins with " + Arrays.asList(proceedingJoinPoint.getArgs()));
    14             result =  proceedingJoinPoint.proceed();
    15             //相当于后置返回通知
    16             System.out.println("The method " + method + " ends with " + result);
    17         } catch (NotZeroException e) {
    18             //相当于异常通知
    19             System.out.println("The method " + method + " occur an exception: " + e);
    20             throw new NotZeroException("除数不能为空");
    21         } catch (Throwable e) {
    22             // TODO Auto-generated catch block
    23             e.printStackTrace();
    24         } finally {
    25             //相当于后置通知
    26             System.out.println("The method " + method + " end");
    27         }
    28         return result;
    29     }
    LoggingAspect#Around

    ④ Test 类

    这回Test 类 跟上面的会有些不同

    @ContextConfiguration(locations= {"classpath:applicationContext.xml"})

    这样子加载ApplicationContext 资源

     1 package com.myth.spring.aop.annotion.test;
     2 
     3 import org.junit.Test;
     4 import org.junit.runner.RunWith;
     5 import org.springframework.beans.factory.annotation.Autowired;
     6 import org.springframework.test.context.ContextConfiguration;
     7 import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
     8 
     9 import com.myth.spring.aop.annotion.service.IArithmeticCaculator;
    10 
    11 @RunWith(SpringJUnit4ClassRunner.class)
    12 @ContextConfiguration(locations= {"classpath:applicationContext.xml"})
    13 public class TestAspect {
    14     @Autowired
    15     private IArithmeticCaculator iArithmeticCaculator;
    16     
    17     @Test
    18     public void testAdd() {
    19         iArithmeticCaculator.add(1, 2);
    20     }
    21 
    22     @Test
    23     public void testDiv() {
    24         iArithmeticCaculator.div(1, 0);
    25     }
    26 }
    TestAspect 

    XML配置

     XML 配置其实就是把所有的切面方法写到applicationContext中

    这里就只放上xml 配置文件

     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <beans xmlns="http://www.springframework.org/schema/beans"
     3     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     4     xmlns:context="http://www.springframework.org/schema/context"
     5     xmlns:aop="http://www.springframework.org/schema/aop"
     6     xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
     7         http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
     8         http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
     9 
    10     <bean id="arithmeticCalculator" class="com.myth.spring.AOP.xml.ArithmeticCalculatorImpl">
    11     </bean>
    12     
    13     <bean id="loggingAspect" class="com.myth.spring.AOP.xml.LoggingAspect"></bean>
    14     
    15     <bean id="validation" class="com.myth.spring.AOP.xml.Validation"></bean>
    16     
    17 <!--     配置AOP -->
    18     <aop:config>
    19         <aop:pointcut expression="execution(* com.myth.spring.AOP.xml.ArithmeticCalculator.*(.. ))" 
    20         id="pointcut"/>
    21         <aop:aspect order="2" ref="loggingAspect" >
    22         <aop:before method="beforeMethod" pointcut-ref="pointcut"/>
    23 <!--         <aop:after method="afterMethod" pointcut-ref="pointcut"/> -->
    24         <aop:after-returning method="afterReturningMethod" pointcut-ref="pointcut" returning="result"/>
    25         <aop:after-throwing method="afterThrowingMethod" pointcut-ref="pointcut" throwing="ex"/>
    26         </aop:aspect>
    27         <aop:aspect order="1" ref="validation" >
    28         <aop:before method="validate" pointcut-ref="pointcut"/>
    29         </aop:aspect>
    30     </aop:config>
    31     
    32 </beans>
    applicationContext.xml

    总结:  我是建议用第一种方法  

    首先界面干净清晰 不用太依赖于xml文件

    其次 因为我这个案例比较小, 如果切面有很多  其他的写法会有很多切面在XML 中存在  对了 我们可以设置Order 属性来确定切面的顺序, 在 XML 中 我有表现出这种形式

    当然了  每种写法都可以, 大家择其喜欢的吧

  • 相关阅读:
    DNS解析的并发性
    Pycharm(Jetbrains IDE)Debian buster Navigate Back/Forward (Ctrl+Alt+Left/Right)不好使的解决方法
    Linux命令行登录时的提示信息
    cmake编译Qt5
    cmake使用ccache
    bash 脚本所在文件夹
    gnome desktop
    gnome caps lock 和 num lock 键状态
    oracle 日期、月份处理
    独夜行
  • 原文地址:https://www.cnblogs.com/mythdoraemon/p/7565275.html
Copyright © 2011-2022 走看看