Spring-AOP

来源:互联网 发布:网络男歌手好听的歌 编辑:程序博客网 时间:2024/05/29 11:31
记得上小学时候,上课前班长或者学习委员都会带头喊:起立,然后童鞋们起立齐喊:老师好才开始上课,下课同样起立喊老师再见,整节课才算完成。其实这是一种仪式,并不是某一位老师特别教授的技能,但又必须做,而且无论什么课程都需要举行,这种就类似于程序中的非核心业务,不能与核心业务混为一体,只是在需要出现的地方出现,为处理这种矛盾,从而就有了专门处理的方法或理念,叫面向切面编程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 @EnableAspectJAutoProxy10 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 @Component12 @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 @Autowired16 private Teacher t;17     @Test18     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.xsd14     http://www.springframework.org/schema/context 15     http://www.springframework.org/schema/context/spring-context.xsd16     http://www.springframework.org/schema/jdbc 17     http://www.springframework.org/schema/jdbc/spring-jdbc.xsd18     http://www.springframework.org/schema/aop19     http://www.springframework.org/schema/aop/spring-aop.xsd20     http://www.springframework.org/schema/jee 21     http://www.springframework.org/schema/jee/spring-jee.xsd22     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 @EnableAspectJAutoProxy10 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 @Autowired16 private Teacher t;17     @Test18     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

0 0
原创粉丝点击