ssm

Spring aop<4>

2017-08-13  本文已影响18人  天空在微笑

AOP(Aspect Oriented Programing)
面向切面编程采用横向抽取机制,以取代传统的纵向继承体系的重复性代码(如性能监控/事务管理/安全检查/缓存实现等)

Spring 实现AOP方式有cglib和Java动态代理,默认实现方式为Java动态代理。

AOP相关术语

  1. 引入图中的包


    image.png
  2. 在spring配置文件中配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:aop="http://www.springframework.org/schema/aop"    
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                        http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
                        http://www.springframework.org/schema/context
                        http://www.springframework.org/schema/context/spring-context-4.0.xsd>
 <!--和schema一起启动@Aspectj支持-->
    <aop:aspectj-autoproxy/>

或者

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:aop="http://www.springframework.org/schema/aop"    
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                        http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
                        http://www.springframework.org/schema/context
                        http://www.springframework.org/schema/context/spring-context-4.0.xsd>
 <!--第二种方式启动@Aspectj支持-->
<bean class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator"/>
</beans>
  1. 使用@Aspect定义一个切面类
@Aspect
public class TestAspectModel {
...
}
  1. 定义一个需要增强的类
@Component(value = "firstaspect")
public class Firstaspect {
    public void noReturn() {
        System.out.println("执行方法noReturn()");
    }
    public String hasReturn(String argument) {
        System.out.println("执行方法hasReturn()"+argument);
        return " (hasReturn方法执行返回值) "+argument;
    }

    public void throwException() {
        System.out.println("执行方法throwException()");
        throw new IllegalArgumentException("i am a runtime exception");
    }
}
  1. 定义增强方法
    增强方式有:

@Before
@AfterReturning
@AfterThrowing
@After
@Around

5.1 @Before

@Aspect
public class TestAspectModel {

    @Before("execution(* com.lq.play.model.*.*(..))")
    public void before() {
        System.out.println("Before!");
    }
}

测试用例

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:config/spring/spring-servlet.xml"})
public class ApplicationTest {

    @Autowired
    private Firstaspect firstaspect;

    @Test
    public void test() throws Exception {
        firstaspect.hasReturn("");
    }
}

执行结果:

Before!
执行方法hasReturn()

@Before 增强只能在目标方法执行之前织入增强,如果需要阻止目标方法执行,可通过抛出一个异常来实现。
5.2 @AfterReturning
@AfterReturning增强方法将在目标方法正常完成后被织入。
@AfterReturning注解有两个属性:

@AfterReturning(returning = "returnValue",pointcut = "execution(* com.lq.play.model.*.*(..))")
//@AfterReturning(returning = "returnValue",pointcut = "myPointCut()")
public void afterReturning(JoinPoint joinPoint,Object returnValue) {
    System.out.println("afterReturning!");
    System.out.println("afterReturning!: 目标方法返回值:"+returnValue);
    System.out.println("afterReturning! 被织入增强处理的目标方法为:"+joinPoint.getSignature().getName());
    System.out.println("afterReturning! 被织入增强处理的目标方法的参数为:"+joinPoint.getArgs());
    System.out.println("afterReturning! 被织入增强处理的目标对象为:" +joinPoint.getTarget());
}

执行结果:

执行方法hasReturn()
afterReturning!
afterReturning!: 目标方法返回值: (hasReturn方法执行返回值)
afterReturning! 被织入增强处理的目标方法为:hasReturn
afterReturning! 被织入增强处理的目标方法的参数为:[Ljava.lang.Object;@2a8448fa
afterReturning! 被织入增强处理的目标对象为:com.lq.play.model.Firstaspect@6f204a1a

5.3 @AfterThrowing
@AfterThrowing增强方法将在目标方法正常完成后被织入。
@AfterThrowing注解有两个属性:

 @AfterThrowing(throwing = "ex",pointcut = "execution(* com.lq.play.model.*.*(..))")
    public void afterThrowing(IllegalArgumentException ex) {
        System.out.println("afterThrowing:"+ex);
    }

向Firstaspect添加抛异常方法

 public void throwException() {
        System.out.println("执行方法throwException()");
        throw new IllegalArgumentException("i am a runtime exception");
    }

测试用例

@ContextConfiguration(locations = {"classpath:config/spring/spring-servlet.xml"})
public class ApplicationTest {

    @Autowired
    private Firstaspect firstaspect;

    @Test
    public void test() throws Exception {
//        firstaspect.hasReturn("");
        firstaspect.throwException();
    }
}

返回结果:

执行方法throwException()
afterThrowing:java.lang.IllegalArgumentException: i am a runtime exception

java.lang.IllegalArgumentException: i am a runtime exceptionat com.lq.play.model.Firstaspect.throwException(Firstaspect.java:22)at com.lq.play.model.Firstaspect$$FastClassBySpringCGLIB$$89d307c5.invoke(<generated>)at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)...

5.4 @After
@AfterReturning增强处理在目标方法成功执行后才会被织入。
@After增强处理不管目标方法成功与否,它都会被织入,和异常捕捉的finally关键字类似。
增强处理类:
```java
@Aspect
public class TestAspectModel {

    @After("execution(* com.lq.play.model.*.*(..))")
    public void after() {
        System.out.println("After!");
    }

    @AfterReturning(returning = "returnValue", pointcut = "execution(* com.lq.play.model.*.*(..))")
    public void afterReturning(JoinPoint joinPoint, Object returnValue) {
        System.out.println("afterReturning!");
        System.out.println("afterReturning!: 目标方法返回值:" + returnValue);
        System.out.println("afterReturning! 被织入增强处理的目标方法为:" + joinPoint.getSignature().getName());
        System.out.println("afterReturning! 被织入增强处理的目标方法的参数为:" + joinPoint.getArgs());
        System.out.println("afterReturning! 被织入增强处理的目标对象为:" + joinPoint.getTarget());
    }
}

测试用例

@ContextConfiguration(locations = {"classpath:config/spring/spring-servlet.xml"})
public class ApplicationTest {

    @Autowired
    private Firstaspect firstaspect;

    @Test
    public void test() throws Exception {
//        firstaspect.hasReturn("");
        firstaspect.throwException();
    }
}

返回结果

执行方法throwException()
After!
java.lang.IllegalArgumentException: i am a runtime exception
at com.lq.play.model.Firstaspect.throwException(Firstaspect.java:22)at com.lq.play.model.Firstaspect$$FastClassBySpringCGLIB$$89d307c5.invoke(<generated>)at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)

执行了@After增强,没有执行@AfterReturning

5.6 @Around
这个是功能最强大的增强处理,既可以在执行方法前织入增强动作,也可以在执行目标方法之后织入增强动作。

@Aspect
public class TestAspectModel {
    @Around("execution(* com.lq.play.model.*.*(..))")
    public Object around(ProceedingJoinPoint pjp) throws Throwable{

        System.out.println("around!");
        System.out.println("around! 被织入增强处理的目标方法为:"+pjp.getSignature().getName());
        System.out.println("around! 被织入增强处理的目标方法的参数为:"+Arrays.toString(pjp.getArgs()));
        System.out.println("around! 被织入增强处理的目标对象为:" +pjp.getTarget());
        System.out.println("around!");
        Object[] args = pjp.getArgs();
        if (args != null && args.length > 0) {
            args[0]="around 增加的参数前缀"+args[0];
        }

        Object returnValue =  pjp.proceed(args);

        return "around 增加的执行后前缀"+(String)returnValue;
    }
}

目标方法

   public String hasReturn(String argument) {
        System.out.println("执行方法hasReturn()"+"传入的参数值:"+argument);
        return "(hasReturn方法执行返回值)"+argument;
    }

测试用例:

   System.out.println(firstaspect.hasReturn(""));

执行结果:

around!
around! 被织入增强处理的目标方法为:hasReturn
around! 被织入增强处理的目标方法的参数为:[Ljava.lang.Object;@533bda92
around! 被织入增强处理的目标对象为:com.lq.play.model.Firstaspect@304bb45b
around!
执行方法hasReturn()传入的参数值:around 增加的参数前缀
around 增加的执行后前缀(hasReturn方法执行返回值)around 增加的参数前缀

五个增强都加入执行结果

around!
around! 被织入增强处理的目标方法为:hasReturn
around! 被织入增强处理的目标方法的参数为:[Ljava.lang.Object;@7bd7d6d6
around! 被织入增强处理的目标对象为:com.lq.play.model.Firstaspect@43f02ef2
around!
Before!
执行方法hasReturn()传入的参数值:around 增加的参数前缀
After!
afterReturning!
afterReturning!: 目标方法返回值:around 增加的执行后前缀(hasReturn方法执行返回值)around 增加的参数前缀
afterReturning! 被织入增强处理的目标方法为:hasReturn
afterReturning! 被织入增强处理的目标方法的参数为:[Ljava.lang.Object;@5b7a7f33
afterReturning! 被织入增强处理的目标对象为:com.lq.play.model.Firstaspect@43f02ef2

执行了

  1. 访问目标方法的参数
    在增强方法里第一个参数定义为JoinPoint类型(ProceedingJoinPoint 即为JoinPoint子类),JoinPoint代表了织入增强处理的连接点。JoinPoint包含如下几个方法。

示例如@Around的增强方法:

 @Around("execution(* com.lq.play.model.*.*(..))")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {

        System.out.println("around!");
        System.out.println("around! 被织入增强处理的目标方法为:" + pjp.getSignature().getName());
        System.out.println("around! 被织入增强处理的目标方法的参数为:" + Arrays.toString(pjp.getArgs()));
        System.out.println("around! 被织入增强处理的目标对象为:" + pjp.getTarget());
        System.out.println("around!");
        Object[] args = pjp.getArgs();
        if (args != null && args.length > 0) {
            args[0] = "around 增加的参数前缀" + args[0];
        }

        Object returnValue = pjp.proceed(args);

        return "around 增加的执行后前缀" + (String) returnValue;
    }

可以指定织入优先级

可以为表达式指定参数,如下:

 @AfterReturning(returning = "returnValue", pointcut = "execution(* com.lq.play.model.*.*(..))&&args(arg1)")
//@AfterReturning(returning = "returnValue",pointcut = "myPointCut()")
    public void afterReturning(JoinPoint joinPoint, Object returnValue,String arg1) {}
  1. 定义切入点
    当多个表达式相同时,可以定义一个
 @Pointcut("execution(* com.lq.play.model.*.*(..))")
 public void myPointCut() {
 }

然后其它引入即可

 @AfterReturning(returning = "returnValue",pointcut = "myPointCut()")
  1. 也可以使用xml配置
  <bean name="testAspectModel" class="com.lq.play.aspect.TestAspectModel" />
    <!-- 进行 aop 的配置 -->
    <aop:config><!-- 配置切入点表达式 :哪些类的方法需要进行增强 哪些类的方法需要进行增强 -->
        <aop:pointcut expression="execution(* com.lq.play.model.*.*(..))" id="pointcut1"/>
        <aop:pointcut expression="execution(* com.lq.play.model.*.*(..))" id="pointcut2"/>
        <!-- 配置切面 -->
        <aop:aspect ref="testAspectModel">
            <aop:before method="before" pointcut-ref ="pointcut1" />
            <aop:after-returning method ="afterReturning" pointcut-ref ="pointcut1" returning="returnValue" />
            <aop:around method="around" pointcut-ref ="pointcut1" />
            <aop:after-throwing method ="afterThrowing" pointcut-ref ="pointcut1" throwing="ex"/>
            <aop:after method="after" pointcut-ref ="pointcut1" />
        </aop:aspect>
    </aop:config>

<aop:aspect .../>有如下三个属性:

这几个元素都不支持子元素,但有如下属性:

上一篇 下一篇

猜你喜欢

热点阅读