AOP技术,它利用一种称为"横切"的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其命名为"Aspect",即切面。所谓"切面",简单说就是那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块之间的耦合度,并有利于未来的可操作性和可维护性。
1、切面(Aspect)
一个服务层方法增强的一类功能点,一类功能实现就是切面,里面可以定义多个advice
事务管理、日志管理、异常控制 : 都是切面
2、连接点(Joinpoint)
就是对应的具体的被代理的方法 : execute()
Joinpoint跟我们具体的被代理的方法一一对应
3、切点(Pointcut)
可以认为是连接点(joinpoint)的集合,是很多方法的集合
4、增强\通知(Advice)
所谓通知指的就是指拦截到连接点之后要执行的代码,通知分为前置、后置、异常、最终、环绕通知五类
5、Advisor
advice和pointcut的组合或封装,Advisor可以认为它是一个只有一个advice的切面
6、引入(Introduction)
实际上也是一个类的扩展,可以认为往这个被代理类中加入动态方法
在不修改代码的前提下,引入可以在运行期为类动态地添加一些方法或字段
所以进行AOP编程的关键就是定义切入点和定义增强处理,一旦定义了合适的切入点和增强处理,AOP框架将自动生成AOP代理,即:代理对象的方法=增强处理+被代理对象的方法。
一、aop的xml配置元素
<aop:pointcut>:用来定义切入点,该切入点可以重用;
<aop:advisor>:用来定义只有一个通知和一个切入点的切面;
//下面是另外一种定义方式 如上图 用的比较多的是上面那种定义方式,例如tx(事物通知)
<aop:aspect>:用来定义切面,该切面可以包含多个切入点和通知,而且标签内部的通知和切入点定义是无序的;
和advisor的区别就在此,advisor只包含一个通知和一个切入点。
第二种方式例子:
package com.dongnao.jack.aop;
import org.aspectj.lang.ProceedingJoinPoint;
public class AopAspectj {
public void before() {
System.out.println("开启事务");
}
public void after() {
System.out.println("关闭事务");
}
public void afterReturning() {
System.out.println("返回后通知");
}
public void afterthrowing() {
System.out.println("抛出后通知");
}
public void around(ProceedingJoinPoint point) {
System.out.println("前置环绕通知");
try {
point.proceed();
}
catch (Throwable e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("后置环绕通知");
}
}
<bean id="myaspectj" class="com.dongnao.jack.aop.AopAspectj"></bean>
<aop:config>
<aop:aspect id="txAspect" ref="myaspectj" order="2">
<!-- 在此处定义的pointcut是全局的pointcut只供当前的aspect使用 id:表示这个pointcut的名称,以方便使用 -->
<aop:pointcut id="myMethod2" expression="execution(public * com.dongnao.jack.service..*.*(..))" />
<!-- 定义advice时的参数
method:切面逻辑的方法名称(切面类中的方法名)
pointcut-ref:表示引用哪个pointcut(要求已经在上面定义好了)
pointcut:定义一个pointcut -->
<!--
<aop:before method="before" pointcut-ref="myMethods"/>
<aop:after-returning method="afterReturning" pointcut="execution(public * com.dongnao.jack.service..*.*(..))"/>
<aop:after method="after" pointcut-ref="myMethod2"/>
<aop:after-throwing method="afterthrowing" pointcut-ref="myMethods"/>
<aop:around method="around" pointcut-ref="myMethod2"/>
<aop:before method="before" pointcut="execution(public * com.dongnao.jack.aop..*.*(..))"/>
-->
下面第一行是自己定义切点,第二行用公用切点,通知方法用的切面定义的方法
<aop:before method="before" pointcut="execution(public * com.dongnao.jack.service..*.*(..))"/>
<aop:after method="after" pointcut-ref="myMethod2"/>
</aop:aspect>
</aop:config>
第一种方式:也是我们常用的方式
自己定义的通知必须要实现MethodInterceptor
public class MyInterceptor implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
before();
Object result = invocation.proceed();
return result;
}
private void before() {
System.out.println("自定义MethodInterceptor前置增强");
}
}
<bean id="myInterceptor" class="com.dongnao.jack.interceptor.MyInterceptor"></bean>
<aop:config>
<aop:advisor advice-ref="myInterceptor" pointcut="execution(public * com.dongnao.jack.service..*.*(..))" order="1"/>
</aop:config>
二、引入的使用
<bean id="myintroduction" class="com.dongnao.jack.aop.IntroductionClass"></bean>
<aop:declare-parents types-matching="com.dongnao.jack.service.MyServiceImpl"
implement-interface="com.dongnao.jack.aop.IntroductionIntf"
delegate-ref="myintroduction"/>
动态的将 MyServiceImpl 这个接口实现了IntroductionIntf 这个接口,里面的内容为myintroduction这个类实现类的内容
三、aop链式拦截器
自定义aop链式拦截器要实现MethodInterceptor这个接口
自定义请求响应拦截器实现HandlerInterceptor这个接口