Spring-AOP

记得上小学时候,上课前班长或者学习委员都会带头喊:起立,然后童鞋们起立齐喊:老师好才开始上课,下课同样起立喊老师再见,整节课才算完成。其实这是一种仪式,并不是某一位老师特别教授的技能,但又必须做,而且无论什么课程都需要举行,这种就类似于程序中的非核心业务,不能与核心业务混为一体,只是在需要出现的地方出现,为处理这种矛盾,从而就有了专门处理的方法或理念,叫面向切面编程AOP,Spring支持AOP,下面就以学生上课为例进行示范:


 

JavaConfig:

 1 package com.spring.config;
 2 
 3 import org.springframework.context.annotation.ComponentScan;
 4 import org.springframework.context.annotation.Configuration;
 5 import org.springframework.context.annotation.EnableAspectJAutoProxy;
 6 
 7 @Configuration
 8 @ComponentScan(basePackages={"com.spring"})
 9 @EnableAspectJAutoProxy
10 public class CreatureSpingConfig {
11 }
配置类
 1 package com.spring.aop;
 2 
 3 import org.aspectj.lang.ProceedingJoinPoint;
 4 import org.aspectj.lang.annotation.After;
 5 import org.aspectj.lang.annotation.Around;
 6 import org.aspectj.lang.annotation.Aspect;
 7 import org.aspectj.lang.annotation.Before;
 8 import org.aspectj.lang.annotation.Pointcut;
 9 import org.springframework.stereotype.Component;
10 
11 @Component
12 @Aspect//需要引入aspectjrt-1.*.*.jar,此处版本需要和jdk版本匹配
13 public class Sophomore implements Student{
14 /**
15 * 定义切点,下面的没有方法体的方法只是相当于一个别名
16 */
17 @Pointcut("execution(* com.spring.aop.ChineseTeacher.teach(..))")
18 public void begin(){}
19 @Pointcut("execution(* com.spring.aop.ChineseTeacher.classOver(..))")
20 public void over(){}
21 
22 @Before("begin()")
23 public void beforeTest(){
24 System.out.println("班长:上课!\n童鞋们:老师好!");
25 }
26 @Around("begin()")
27 public void aroundTest(ProceedingJoinPoint p){
28 try {
29 System.out.println("叮铃铃~");
30 p.proceed();//继续执行连接点的方法,如果不写表示不调用这个连接点的方法
31 } catch (Throwable e) {
32 System.out.println("自习ing");//上课出错则自习
33 }
34 }
35 @Before("over()")
36 public void ringTest(){
37 System.out.println("叮铃铃~");
38 }
39 @After("over()")
40 public void afterTest(){
41 System.out.println("班长:下课!\n童鞋们:老师再见!");
42 }
43 }
学生实现类
 1 package com.spring.aop;
 2 
 3 import org.springframework.stereotype.Component;
 4 
 5 @Component
 6 public class ChineseTeacher implements Teacher{
 7     @Override
 8     public void teach() {
 9         System.out.println("同学们好,今天我们来学习一首诗《锄禾》...");
10     }
11     public void classOver(){
12         System.out.println("今天先讲到这里,同学们下课!");
13     }
14 }
教师实现类
 1 package com.spring.test;
 2 
 3 import org.junit.Test;
 4 import org.junit.contrib.java.lang.system.StandardOutputStreamLog;
 5 import org.junit.runner.RunWith;
 6 import org.springframework.beans.factory.annotation.Autowired;
 7 import org.springframework.test.context.ContextConfiguration;
 8 import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
 9 
10 import com.spring.aop.Teacher;
11 @RunWith(SpringJUnit4ClassRunner.class)
12 @ContextConfiguration(classes=com.spring.config.CreatureSpingConfig.class)
13 public class SpringJunit {
14 public static StandardOutputStreamLog log=new StandardOutputStreamLog();
15 @Autowired
16 private Teacher t;
17     @Test
18     public void notNull() {
19         t.teach();
20         System.out.println("45分钟后...");
21         t.classOver();
22     }
23 }
测试类

XML:

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <beans
 3     xmlns="http://www.springframework.org/schema/beans"
 4     xmlns:c="http://www.springframework.org/schema/c"
 5     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 6     xmlns:p="http://www.springframework.org/schema/p"
 7     xmlns:jdbc="http://www.springframework.org/schema/jdbc"
 8     xmlns:jee="http://www.springframework.org/schema/jee"
 9     xmlns:aop="http://www.springframework.org/schema/aop"
10     xmlns:context="http://www.springframework.org/schema/context"
11     xmlns:conditional="http://www.springframework.org/schema/context"
12     xsi:schemaLocation="http://www.springframework.org/schema/beans 
13     http://www.springframework.org/schema/beans/spring-beans.xsd
14     http://www.springframework.org/schema/context 
15     http://www.springframework.org/schema/context/spring-context.xsd
16     http://www.springframework.org/schema/jdbc 
17     http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
18     http://www.springframework.org/schema/aop
19     http://www.springframework.org/schema/aop/spring-aop.xsd
20     http://www.springframework.org/schema/jee 
21     http://www.springframework.org/schema/jee/spring-jee.xsd
22     http://www.springframework.org/schema/conditional 
23     http://www.springframework.org/schema/conditional/spring-conditional.xsd">
24     <context:annotation-config ></context:annotation-config>
25     <bean id="chineseTeacher" class="com.spring.aop.ChineseTeacher"></bean>
26     <bean id="sophomore" class="com.spring.aop.Sophomore"></bean>
27     <aop:aspectj-autoproxy proxy-target-class="true"/>
28     <aop:config>
29         <aop:aspect ref="sophomore">
30             <aop:pointcut expression="execution(* com.spring.aop.ChineseTeacher.teach(..))" id="begin()"/>
31             <aop:pointcut expression="execution(* com.spring.aop.ChineseTeacher.classOver(..))" id="over()"/>
32             <aop:around method="aroundTest" pointcut-ref="begin()"/>
33             <aop:before method="beforeTest()" pointcut-ref="begin()"/>
34             <aop:before method="ringTest()" pointcut-ref="over()"/>
35             <aop:after method="afterTest()" pointcut-ref="over()"/>
36         </aop:aspect>
37     </aop:config>
38 </beans>
XML

配置类:

 1 package com.spring.config;
 2 
 3 import org.springframework.context.annotation.ComponentScan;
 4 import org.springframework.context.annotation.Configuration;
 5 import org.springframework.context.annotation.EnableAspectJAutoProxy;
 6 
 7 @Configuration
 8 @ComponentScan(basePackages={"com.spring"})
 9 @EnableAspectJAutoProxy
10 public class SpringConfig {
11 }
配置类

学生实现类:

 1 package com.spring.aop;
 2 
 3 import org.aspectj.lang.ProceedingJoinPoint;
 4 import org.aspectj.lang.annotation.After;
 5 import org.aspectj.lang.annotation.Around;
 6 import org.aspectj.lang.annotation.Aspect;
 7 import org.aspectj.lang.annotation.Before;
 8 import org.aspectj.lang.annotation.Pointcut;
 9 import org.springframework.stereotype.Component;
10 public class Sophomore implements Student{
11 public void beforeTest(){
12 System.out.println("班长:上课!\n童鞋们:老师好!");
13 }
14 public void aroundTest(ProceedingJoinPoint p){
15 try {
16 System.out.println("叮铃铃~");
17 p.proceed();//继续执行连接点的方法,如果不写表示不调用这个连接点的方法
18 } catch (Throwable e) {
19 System.out.println("自习ing");//上课出错则自习
20 }
21 }
22 public void ringTest(){
23 System.out.println("叮铃铃~");
24 }
25 public void afterTest(){
26 System.out.println("班长:下课!\n童鞋们:老师再见!");
27 }
28 }
学生实现类

教师实现类:

 1 package com.spring.aop;
 2 
 3 public class ChineseTeacher implements Teacher{
 4     public void teach() {
 5         System.out.println("同学们好,今天我们来学习一首诗《锄禾》...");
 6     }
 7     public void classOver(){
 8         System.out.println("今天先讲到这里,同学们下课!");
 9     }
10 }
教师实现类

测试:

 1 package com.spring.aop;
 2 
 3 import org.junit.Test;
 4 import org.junit.contrib.java.lang.system.StandardOutputStreamLog;
 5 import org.junit.runner.RunWith;
 6 import org.springframework.beans.factory.annotation.Autowired;
 7 import org.springframework.test.context.ContextConfiguration;
 8 import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
 9 
10 import com.spring.aop.Teacher;
11 @RunWith(SpringJUnit4ClassRunner.class)
12 @ContextConfiguration(locations="/spring.xml")
13 public class SpringJunit {
14 public static StandardOutputStreamLog log=new StandardOutputStreamLog();
15 @Autowired
16 private Teacher t;
17     @Test
18     public void notNull() {
19         t.teach();
20         System.out.println("45分钟后...");
21         t.classOver();
22     }
23 }
测试类

结果:

 总结:

  1. @Aspect需要导入aspectjrt.jar;
  2. 在配置类或xml配置文件中应配置@EnableAspectJAutoProxy或<aop:aspectj-autoproxy/>
  3. 需要引入aopaliance.jar,否则会报错:java.lang.ClassNotFoundException: org.aopalliance.intercept.MethodInterceptor
  4. 需要引入aspectjweaver.jar,否则会报错:java.lang.ClassNotFoundException: org.aspectj.weaver.reflect.ReflectionWorld$ReflectionWorldException
  5. 过程中可能出现如下异常:java.lang.IllegalArgumentException: error at ::0 can't find referenced pointcut teach,原因是:aspectjrt.jar版本与jdk版本不一致,解决办法参考:http://www.cnblogs.com/xing901022/p/4267563.html
  6. jar包下载地址:http://mavenrepository.com/
  7. JavaConfig方式中:before方法的优先级比around低
  8. execution(* com.spring.aop.ChineseTeacher.teach(..))扩展

    AOP支持的AspectJ切入点指示符如下:

             execution用于匹配方法执行的连接点;

             within用于匹配指定类型内的方法执行;

             this用于匹配当前AOP代理对象类型的执行方法;注意是AOP代理对象的类型匹配,这样就可能包括引入接口也类型匹配;

             target用于匹配当前目标对象类型的执行方法;注意是目标对象的类型匹配,这样就不包括引入接口也类型匹配;

             args用于匹配当前执行的方法传入的参数为指定类型的执行方法;

             @within用于匹配所以持有指定注解类型内的方法

             @target用于匹配当前目标对象类型的执行方法,其中目标对象持有指定的注解;

             @args用于匹配当前执行的方法传入的参数持有指定注解的执行;

             @annotation用于匹配当前执行方法持有指定注解的方法;

             beanSpring AOP扩展的,AspectJ没有对于指示符,用于匹配特定名称的Bean对象的执行方法;

             reference pointcut表示引用其他命名切入点,只有@ApectJ风格支持,Schema风格不支持。

           AspectJ切入点支持的切入点指示符还有: call、get、set、preinitialization、staticinitialization、initialization、handler、adviceexecution、withincode、cflow、cflowbelow、if、@this、@withincode;但Spring AOP目前不支持这些指示符,使用这些指示符将抛出IllegalArgumentException异常。这些指示符Spring AOP可能会在以后进行扩展。

  9. XML方式中,执行顺序是自上而下,与JavaConfig方式不同;
  10. XML方式中,在<aop:around>标签中,method方法不需加(),无参方法可以,如果是around方法,必须有ProceedingJoinPoint类的参数,因此会报错:

    Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name '(inner bean)#1d03f44': Initialization of bean failed; nested exception is java.lang.IllegalArgumentException: Unable to locate method [aroundTest()] on bean [sophomore]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:547)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:475)
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveInnerBean(BeanDefinitionValueResolver.java:276)
    ... 65 more

posted @ 2016-10-27 16:38  舒山  阅读(419)  评论(0编辑  收藏  举报