1.概念
AOP(Aspect-OrientedProgramming,面向切面编程),可以说是OOP(Object-Oriented Programing,面向对象编程)的补充和完善。 AOP(Aspect Oriented Programming)书面解释是面向切面编程。是Spring核心之一。经常被用来处理事务,日志和其他一些不是主要业务逻辑的需求中。
2.AOP相关概念
1.切面(aspect):要实现的交叉功能,是系统模块化的一个切面或领域。如日志记录。
2.连接点:应用程序执行过程中插入切面的地点,可以是方法调用,异常抛出,或者要修改的字段。
3.通知:切面的实际实现,他通知系统新的行为。如在日志通知包含了实现日志功能的代码,如向日志文件写日志。 通知在连接点插入到应用系统中。
4.切入点:定义了通知应该应用在哪些连接点,通知可以应用到AOP框架支持的任何连接点。
5.引入:为类添加新方法和属性。
6.目标对象:被通知的对象。既可以是你编写的类也可以是第三方类。
7.代理:将通知应用到目标对象后创建的对象,应用系统的其他部分不用为了支持代理对象而改变。
8.织入:将切面应用到目标对象从而创建一个新代理对象的过程。织入发生在目标对象生命周期的多个点上:
编译期:切面在目标对象编译时织入.这需要一个特殊的编译器.
类装载期:切面在目标对象被载入JVM时织入.这需要一个特殊的类载入器.
运行期:切面在应用系统运行时织入.
3.运用场景
AOP具体可以在下面的场景中使用:
Authentication权限 Caching缓存 Contextpassing 内容传递
Errorhandling 错误处理 Lazyloading 懒加载 Debugging 调试
logging,tracing, profiling and monitoring
记录跟踪 优化 校准
Performanceoptimization 性能优化
Persistence 持久化
Resourcepooling 资源池
Synchronization 同步
Transactions事务
下面使用一个简单的场景来说明AOP。该场景是这样的,在一个系统中,对于用户的某些操作需要记录日志,例如,用户删除,修改某些敏感数据。
想一想如果我们不使用AOP会怎么处理呢?一般情况下,我们会新建一个类LogHandler,然后在该类中新建一个方法,暂且叫做logDetail方法,然后在需要进行写日志的地方调用该方法。这样做的后果是在具体的业务方法中会到处充斥着不是正常业务逻辑的logDetail方法,代码的可读性,可维护性都不是很好,同时这种处理log的方法已经侵入到业务逻辑中,耦合性太高。
如果我们使用AOP,那么我们就可以在不影响程序的业务完整性的情况,把写日志这个需求完成。而要实现AOP也仅仅只要在Spring中配置一下即可(xml形式或者annotation形式)。这样处理是没有侵入性的,不会去修改原有的代码,耦合性低。注意使用Aop也是需要新建Loghandler类和logDetail方法。
4.优点
提高代码的可读性,可维护性,同时又降低了耦合度,在不影响程序的业务完整性的情况下,把任务完成
5.实例(织入前置通知)需要在在调用TestService对象的sayHello方法之前,执行日志操作
类TestService
<span style="font-size:18px;">package com.aop.spring; public class TestService implements TestServiceInter,TestServiceInter2{ private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } public void sayHello() { // TODO Auto-generated method stub System.out.println("hello"+name); } public void sayBye() { // TODO Auto-generated method stub System.out.println("bye"+name); } }</span>接口TestServiceInter
<span style="font-size:18px;">package com.aop.spring; public interface TestServiceInter { public void sayHello(); }</span>通知类MyMethodBeforeAdvice
<span style="font-size:18px;">package com.aop.spring; import java.lang.reflect.Method; import org.springframework.aop.MethodBeforeAdvice; public class MyMethodBeforeAdvice implements MethodBeforeAdvice { public void before(Method method, Object[] args, Object target) throws Throwable { // TODO Auto-generated method stub System.out.println("日志操作"+method.getName()); } }</span>
package com.aop.spring; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class App { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub ApplicationContext app=new ClassPathXmlApplicationContext("applicationContext.xml"); TestServiceInter testServiceInter=(TestServiceInter) app.getBean("myProxyFactoryBean"); testServiceInter.sayHello(); //TestServiceInter2 testServiceInter2=(TestServiceInter2) app.getBean("myProxyFactoryBean"); //testServiceInter2.sayBye(); } }ApplicationContext.xml
<span style="font-size:18px;"><?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-3.0.xsd"> <span style="color:#ff0000;"><strong><!-- 配置被代理对象 --></strong></span> <bean id="testService" class="com.aop.spring.TestService"> <property name="name" value="cgf" /> </bean> <strong><span style="color:#ff0000;"><!-- 配置前置通知 --></span></strong> <bean id="myMethodBeforeAdvice" class="com.aop.spring.MyMethodBeforeAdvice"></bean> <span style="color:#ff0000;"><strong><!-- 配置代理对象 --></strong></span> <bean id="myProxyFactoryBean" class="org.springframework.aop.framework.ProxyFactoryBean"> <strong><span style="color:#ff0000;"><!-- 代理的接口集 --></span></strong> <property name="proxyInterfaces"> <list> <value>com.aop.spring.TestServiceInter</value> <value>com.aop.spring.TestServiceInter2</value> </list> </property> <span style="color:#ff0000;"><strong><!-- 前置通知织入到代理对象 --></strong></span> <property name="interceptorNames"> <list> <value>myMethodBeforeAdvice</value> </list> </property> <span style="color:#ff0000;"><strong><!-- 配置被代理对象 --></strong></span> <property name="target" ref="testService"> </property> </bean> </beans></span>