AOP的意思的面向切面编程,有的业务场景都需要应用重复的代码,比如登录,开启事务,结束事务,日记记录等等。这时候我们可以将这部分代码抽象成一个切面,然后进行注入。
我们所说的重复代码就类似代码A和代码B。
而AOP增强是对原有程序内部注入一些逻辑代码来增强原有程序功能。
AOP增强分为五种类型:
- 前置增强:在目标方法执行前面注入代码进行增强。
- 后置增强:在目标方法执行后面注入代码进行增强。
- 异常抛出增强:在目标方法抛出异常后注入代码进行增强。
- 引介增强:在目标类中添加一些方法和属性。
- 环绕增强:在目标方法执行前和执行后注入代码进行增强。
环绕增强是AOP联盟的api接口,而其他四种都是Spring定义的api接口。
引介增强与其他增强不同的是引介增强是针对于类的而其他增强是针对于方法。
但是Spring中只支持对方法的增强
* 前置增强如果出现异常会阻止目标方法的执行。
具体实现是由ProxyFactory将增强类注入至原有程序的。
其实ProxyFactory代理技术就是利用jdk代理或者cglib代理的技术,将增强应用到目标类当中。
Spring定义的AOP Proxy类具有两个final类型的实现类,如下图所示:
其中:
Cglib2AopProxy是使用cglib代理技术来创建代理
JdkDynamicAopProxy是使用jdk代理技术来创建代理
使用JDK代理来实现上面的代码则为:
//创建代理工厂对象
ProxyFactory factory=new ProxyFactory();
//设置代理接口
factory.setInterfaces(target.getClass().getInterfaces());
//设置代理类
factory.setTarget(target);
//设置增强类
factory.addAdvice(advice);
使用CGLib代理则为:
ProxyFactory factory=new ProxyFactory();
//设置代理接口
factory.setInterfaces(target.getClass().getInterfaces());
//启用cglib代理方式
factory.setOptimize(true);
//设置代理类
factory.setTarget(target);
//添加增强类
factory.addAdvice(advice);
同时也可以使用配置文件进行增强:
ProxyFactory的常用属性:
target:我们需要代理的目标对象 proxyInterfaces:代理所要实现的接口,可以是多个接口
interceptorNames:需要织入的目标对象的Bean的列表(增强类的Bean列表),使用Bean的名称来指定。
singleton:确定返回的代理是不是单实例的,系统默认返回的是单实例的。
optimize:当值为true时,强制使用cglib代理。当是singleton的实例时我们推荐使用cglib代理,当是其他作用域的时候,推荐使用JDK的代理。原因是cglib创建代理速度比较慢,但是运行效率高。JDK代理则刚好相反。
proxyTargetClass:是否对类进行代理而不是对接口进行代理,当值为true的时候使用cglib代理
<?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:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="gerrtingBefore" class="cn.lovepi.chapter07.aop.advice.GreetingBeforeAdvice"/>
<bean id="target" class="cn.lovepi.chapter07.aop.advice.NativeWaiter"/>
<bean id="waiter" class="org.springframework.aop.framework.ProxyFactoryBean"
p:proxyInterfaces="cn.lovepi.chapter07.aop.advice.Waiter"
p:interceptorNames="gerrtingBefore"
p:target-ref="target"
/>
</beans>
对应的测试文件:
public class TestBeforeAdviceByXml {
public static void main(String[] args){
String path="src/conf/conf-advice.xml";
ApplicationContext context=new FileSystemXmlApplicationContext(path);
Waiter waiter=context.getBean("waiter",Waiter.class);
waiter.greetTo("icarus");
waiter.serverTo("icarus");
}
}
总结:
增强其实就是对原有的方法或类动态增加功能,可为方法执行前后以及所抛出的异常进行逻辑处理。实现增强的方式有两种:代码方式和XML配置文件方式,建议在以后开发中使用后者,这样可以避免代码的耦合度,方便后期维护。