一、AOP 是什么?
AOP 是Aspect Oriented Programaing 的简称,意思是面向切面编程,AOP的应用场合是受限的,一般只适合于那些具有横切逻辑的应用场合:如性能检测、访问控制、事务管理以及日志记录。
二、AOP 术语
1、连接点: 程序执行的某个特定位置,如类开始初始化前,类初始化后、类某个方法调用前、调用后、方法抛出异常后;一个类或一断程序代码拥有一些具有边界性质的特定点,这些代码中的特定点就称为连接点。
2、切点
3、增强(Advice)
4、目标对象
5、引介(Introduction)
6、织入(Weaving)
7、代理(Proxy)
8、切面(Aspect)
三、基于@AspectJ的AOP
一个简单的例子
定义一个接口和实现类,作为增强的目标对象.
package com.baobaotao; public interface Waiter { public void greetTo(String clientName); public void serveTo(String clientName); }
package com.baobaotao; public class NaiveWaiter implements Waiter { public void greetTo(String clientName) { System.out.println("NaiveWaiter:greet to "+clientName+"..."); } public void serveTo(String clientName) { System.out.println("NaiveWaiter:serving "+clientName+"..."); } public void smile(String clientName,int times){ System.out.println("NaiveWaiter:smile to "+clientName+ times+"times..."); } }然后,我们通过@Aspect注解定义一个切面,里面包含切点、增强类型和增强的横切逻辑.
package com.baobaotao.aspectj; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; @Aspect //(1)通过该注解将PreGreetingAspect标识为一个切面 public class PreGreetingAspect { @Before("execution(* greetTo(..))")//(2)定义切点和增强类型(前置增强before) public void beforeGreeting(){//(3)增强的横切逻辑 System.out.println("How are you!"); } }
我们通过org.springframework.aop.aspectj.annotation.AspectJProxyFactory 为NativeWaiter生成织入PreGreetingAspect切面的代理,如下:
package com.baobaotao.aspectj; import org.springframework.aop.aspectj.annotation.AspectJProxyFactory; import com.baobaotao.NaiveWaiter; import com.baobaotao.Waiter; public class AspectJProxyTest { public static void main(String[] args) { Waiter target=new NaiveWaiter(); AspectJProxyFactory factory=new AspectJProxyFactory(); //设置目标对象 factory.setTarget(target); //添加切面类 factory.addAspect(PreGreetingAspect.class); //生成织入切面的代理对象 Waiter proxy=factory.getProxy(); proxy.greetTo("John"); proxy.serveTo("John"); } }运行后输出:
log4j:WARN No appenders could be found for logger (org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory). log4j:WARN Please initialize the log4j system properly. How are you! NaiveWaiter:greet to John... NaiveWaiter:serving John...
至此代理对象的greeTo方法已经织入了切面类所定义的增强逻辑了.
四、如何通过配置使用@AspectJ切面
前面是使用编程方式织入切面 ,一般情况下我们是通过Spring的配置完成切面的织入的工作. 使用AOP命名空间,自动将切面织入到目标Bean中.
<?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-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"> <!-- 基于@Aspect切面的驱动器 --> <aop:aspectj-autoproxy/> <!-- 目标Bean --> <bean id="waiter" class="com.baobaotao.NaiveWaiter"/> <!-- 使用了@Aspect注解的切面类 --> <bean class="com.baobaotao.aspectj.PreGreetingAspect" /> <!-- 自动代理创建器,自动将@Aspect注解切面类织入到目标Bean中 --> <!-- 不使用aop命名空间 --> <!-- <bean class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator"/> --> </beans>
注解:在配置文件中引入aop命名空间,然后通过aop命名空间的<aop:aspectj-autoproxy/> 自动为Spring容器中那些匹配@Apsect切面的Bean创建代理,完成切面织入。当然,Spring在内部依旧采用AnnotationAwareAspectJAutoProxyCreator
进行自动代理的创建工作,但具体的实现细节已经被<aop:aspectj-autoproxy/> 隐藏起来了.
<aop:aspectj-autoproxy/>有一个proxy-target-class属性,默认为false,表示使用JDK动态代理织入增强,当配置为<aop:aspectj-autoproxy proxy-target-class ="true">时,表示使用CGLib动态代理技术织入增强。不过即使proxy-target-class设置为false,如果目标类设有声明接口,则Spring将自动使用CGLib动态代理。
下面我们对上面的配置进行测试:
package com.baobaotao.aspectj; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.baobaotao.Waiter; public class TestPreGreetingAspect { public static void main(String[] args) { ApplicationContext ctx=new ClassPathXmlApplicationContext("com/baobaotao/aspectj/aop.xml"); Waiter waiter=(Waiter) ctx.getBean("waiter"); waiter.greetTo("Tom"); waiter.serveTo("Tom"); } }
输出:
log4j:WARN No appenders could be found for logger (org.springframework.core.env.StandardEnvironment). log4j:WARN Please initialize the log4j system properly. How are you! NaiveWaiter:greet to Tom... NaiveWaiter:serving Tom...