前言
我们知道,使用面向对象编程(OOP)有一些弊端,当需要为多个不具有继承关系的对象引入一个公共的行为时,例如日志、安全检查等,我们只有在每个对象里引用公共的行为,这样程序中就产生了大量的重复代码,程序就不便于维护了,所以就有了一个面向对象编程的补充,即面向切面编程(AOP),AOP所关注的方向是横向的,不同于OOP的纵向。
Spring中提供了AOP的实现,在低版本的Spring中定义一个切面比较的麻烦,需要实现特定的接口,并进行一些较为复杂的配置。在Spring2.0中AOP已经焕然一新,使用@AspectJ注解来定义一个切面就可以了。
动态AOP使用示例
(1)创建用于拦截的bean
在实际的工作中,此bean可能是满足业务需要的核心逻辑,例如一个方法中可能封装着某个核心业务,但是,如果我们想要在这个方法前后加入日志来跟踪调试,如果直接修改源码并不符合面向对象的设计方法,而且随意改动原有代码也会造成一定的风险,还好Spring中帮我们做到了这一点。
public class Hello { private String tetStr = "testStr"; public String getTetStr() { return tetStr; } public void setTetStr(String tetStr) { this.tetStr = tetStr; } public void test(){ System.out.println("test"); } }
(2)创建Advisor
Spring中摒弃了最原始的繁杂配置方式而采用@AspectJ注解对POJO进行标注,使得AOP的工作大大简化,例如,在AspectJTest类中,我们要做的就是在所有的类的test方法执行前后分别在控制台中打印出beforeTest和afterTest,同时又使用环绕的方式在所有类的执行前后分别打印出before和after。在此需要注意如果要使用@AspectJ注解需要引入jar包:aspectjweaver-1.8.7.jar
@Aspect public class AspectJTest { @Pointcut("execution(* *.test(..))") public void test(){ } @Before("test()") public void beforeTest(){ System.out.println("beforeTest"); } @After("test()") public void afterTest(){ System.out.println("afterTest"); } @Around("test()") public Object aroundTest(ProceedingJoinPoint point){ System.out.println("before"); Object object = null; try { object = point.proceed(); } catch (Throwable throwable) { throwable.printStackTrace(); } System.out.println("after"); return object; } }
(3)创建配置文件
XML是Spring的基础。尽管Spring一再简化配置,并且大有使用注解取代XML配置之势,但是无论如何,至少现在XML还是Spring的基础。要在Spring中开启AOP功能,还需要在配置文件中做如下的声明:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!--AOP声明 --> <aop:aspectj-autoproxy/> <bean id="hello" class="com.joe.aop.Hello"/> <bean class="com.joe.aop.AspectJTest"/> </beans>
(4)测试。
public static void main(String[] args){ //创建Spring上下文(加载bean.xml) ApplicationContext acx= new ClassPathXmlApplicationContext("spring-config.xml"); Hello hello = (Hello) acx.getBean("hello"); hello.test(); }
运行结果:
before
beforeTest
test
after
afterTest
Spring实现了对所有类的test方法进行增强,使得辅助功能可以独立于核心业务之外,方便与程序的扩展和解耦。
参考:《Spring源码深度解析》 郝佳 编著: