标签:spring aop aspectj joinpoint proceedingjoinpoint
一、Aop原理
(一)动态代理
1、详见:java进阶(七):详解JAVA代理
2、主要是Proxy 与 InvocationHandle r接口
(二)Cglib 实现
1、主要是 Enhancer 和 MethodInterceptor 接口
2、实现代码如下:
<span style="font-size:18px;"> /** * 利用 cglib 实现 * @param targrt * @return */ public static Object getCgProxy(final Object targrt,final Advice advice){ //利用cglib 中的Enhancer Enhancer enhancer = new Enhancer(); //把目标类设置为代理的父类(继承目标类,覆盖其所有非final的方法) enhancer.setSuperclass(targrt.getClass()); //设置回调 enhancer.setCallback(new MethodInterceptor() {//实现MethodInterceptor 接口 @Override public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { Object object = null; try{ advice.before(method);//前置 object = methodProxy.invoke(targrt, args); advice.after(method);//后置 }catch (Exception e) { advice.afterThrow(method);//例外 }finally{ advice.afterFinally(method);//最终 } return object; } }); return enhancer.create(); } </span>
1、需要的包:spring的包,还需要 aspectjweaver.jar,aopalliance.jar ,asm.jar 和cglib.jar 。
2、Aop的实现方式:Spring 接口方式,schema配置方式和注解的三种方式
3、概念
1)切面(aspect):用来切插业务方法的类。
2)连接点(joinpoint):是切面类和业务类的连接点,其实就是封装了业务方法的一些基本属性,作为通知的参数来解析。
3)通知(advice):在切面类中,声明对业务方法做额外处理的方法。
4)切入点(pointcut):业务类中指定的方法,作为切面切入的点。其实就是指定某个方法作为切面切的地方。
5)目标对象(target object):被代理对象。
6)AOP代理(aop proxy):代理对象。
7)前置通知(before advice):在切入点之前执行。
8)后置通知(after returning advice):在切入点执行完成后,执行通知。
9)环绕通知(around advice):包围切入点,调用方法前后完成自定义行为。
10、异常通知(after throwing advice):在切入点抛出异常后,执行通知。
二、Spring接口的aop实现
(一)详见:Spring AOP (上)
(二)分析
1、实现依赖比较麻烦,spring定义了一堆通知的接口,只要是实现即可。如前置通知接口 MethodBeforeAdvice
<span style="font-size:18px;">package main.java.com.spring.aop.apj; import java.lang.reflect.Method; import org.springframework.aop.MethodBeforeAdvice; /** * Spring接口的前置通知 * BaseBeforeAdvice * @title * @desc * @author SAM-SHO * @Jan 17, 2015 */ public class BaseBeforeAdvice implements MethodBeforeAdvice { /** * method : 切入的方法 <br> * args :切入方法的参数 <br> * target :目标对象 */ @Override public void before(Method method, Object[] args, Object target) throws Throwable { System.out.println("===========进入beforeAdvice()============ \n"); System.out.print("准备在" + target + "对象上用"); System.out.print(method + "方法进行对 '"); System.out.print(args[0] + "'进行删除!\n\n"); System.out.println("要进入切入点方法了 \n"); } }</span>
2、需要 指定切点:实现接口 MethodBeforeAdvice
<span style="font-size:18px;">/** * 定义一个切点,指定对应方法匹配。来供切面来针对方法进行处理<br> * * 继承NameMatchMethodPointcut类,来用方法名匹配 * * @author * */ public class Pointcut extends NameMatchMethodPointcut { private static final long serialVersionUID = 3990456017285944475L; @SuppressWarnings("rawtypes") @Override public boolean matches(Method method, Class targetClass) { // 设置单个方法匹配 this.setMappedName("delete"); // 设置多个方法匹配 String[] methods = { "delete", "modify" }; //也可以用“ * ” 来做匹配符号 // this.setMappedName("get*"); this.setMappedNames(methods); return super.matches(method, targetClass); } }</span>
三、spring利用aspectj 实现aop
(一)源码
1、业务类(target)
<span style="font-size:18px;">package main.java.com.spring.aop.service; /** * 业务接口 * PersonService * @title * @desc * @author SAM-SHO * @Jan 17, 2015 */ public interface PersonService { /** * 保存用户实体 * @param name */ public void save(String name); /** * 删除用户实体 * @param id */ public void delete(Integer id); /** * 查询编号为id的使用用户姓名 * @param id */ public String queryPersonName(Integer id); /** * 更新实体 * @param name * @param id */ public void update(String name ,Integer id); } </span>
<span style="font-size:18px;">package main.java.com.spring.aop.service.impl; import main.java.com.spring.aop.service.PersonService; /** * 业务实现类 * PersionServiceImpl * @title * @desc * @author SAM-SHO * @Jan 17, 2015 */ public class PersonServiceImpl implements PersonService { @Override public void save(String name) { System.out.println("我是save()方法"); } @Override public void delete(Integer id) { System.out.println("我是 delete() 方法"); } @Override public String queryPersonName(Integer id) { System.out.println("我是 query() 方法"); return "XXX"; } @Override public void update(String name, Integer id) { System.out.println("我是 update() 方法"); } } </span>
<span style="font-size:18px;">package main.java.com.spring.aop.apj; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; /** * * AspectAdvice * @title 切面类 * @desc * @author SAM-SHO * @Jan 11, 2015 */ public class AspectAdvice { /** * 前置通知 * * @param jp */ public void doBefore(JoinPoint jp) { System.out.println("===========进入before advice============ \n"); System.out.println("准备在" + jp.getTarget().getClass() + "对象上用"); System.out.println(jp.getSignature().getName() + "方法进行对 '"); System.out.println(jp.getArgs()[0] + "'进行删除!\n\n"); System.out.println("要进入切入点方法了 \n"); } /** * 后置通知 * * @param jp * 连接点 * @param result * 返回值 */ public void doAfter(JoinPoint jp, String result) { System.out.println("==========进入after advice=========== \n"); System.out.println("切入点方法执行完了 \n"); System.out.print(jp.getArgs()[0] + "在"); System.out.print(jp.getTarget().getClass() + "对象上被"); System.out.print(jp.getSignature().getName() + "方法删除了"); System.out.print("只留下:" + result + "\n\n"); } /** * 环绕通知 * * @param pjp * 连接点 */ public void doAround(ProceedingJoinPoint pjp) throws Throwable { System.out.println("===========进入around环绕方法!=========== \n"); // 调用目标方法之前执行的动作 System.out.println("调用方法之前: 执行!\n"); // 调用方法的参数 Object[] args = pjp.getArgs(); // 调用的方法名 String method = pjp.getSignature().getName(); // 获取目标对象 Object target = pjp.getTarget(); // 执行完方法的返回值:调用proceed()方法,就会触发切入点方法执行 Object result = pjp.proceed(); System.out.println("调用方法结束:之后执行!\n"); System.out.println("输出:" + args[0] + ";" + method + ";" + target + ";" + result + "\n"); } /** * 异常通知 * * @param jp * @param e */ public void doThrow(JoinPoint jp, Throwable e) { System.out.println("删除出错啦"); } }</span>
3、配置。
<span style="font-size:18px;"> <!-- 声明一个业务类的Bean --> <bean id="personService" class="main.java.com.spring.aop.service.impl.PersonServiceImpl" /> <!-- 声明通知类 --> <bean id="aspectAdvice" class="main.java.com.spring.aop.apj.AspectAdvice" /> <aop:config> <aop:aspect id="businessAspect" ref="aspectAdvice"> <!--配置指定切入的对象 --> <aop:pointcut id="point_cut" expression="execution(* main.java.com.spring.aop.service..*.*(..))" /> <!--只匹配add方法作为切入点 --> <!-- <aop:pointcut id="except_add" expression="execution(* aop.schema.*.add(..))" /> --> <!--前置通知 --> <aop:before method="doBefore" pointcut-ref="point_cut" /> <!--后置通知 returning指定返回参数 --> <!-- <aop:after-returning method="doAfter" pointcut-ref="point_cut" returning="result" /> --> <!--环绕 --> <!-- <aop:around method="doAround" pointcut-ref="point_cut"/> --> <!--throw中 --> <!-- <aop:after-throwing method="doThrow" pointcut-ref="point_cut" throwing="e"/> --> </aop:aspect> </aop:config> </span>
4、测试。
<span style="font-size:18px;"> @Test public void sopTest(){ ApplicationContext cxt = new ClassPathXmlApplicationContext("applicationAopContext.xml"); PersonService personService = (PersonService) cxt.getBean("personService"); personService.save("shaoxiaobao..."); // tAspectBusiness.delete("zhaoxioaniu"); } </span>
四、注解实现aop
(一)实现配置
1、开打自动扫描,注解实现Bean的管理与注入。(目标与切面都交由spring管理)
<span style="font-size:18px;"> <!-- 开打自动扫描 --> <context:component-scan base-package="main.java.com.spring" /></span>
2、开发Aop的注解
<span style="font-size:18px;"> <!-- 打开aop 注解 --> <aop:aspectj-autoproxy /></span>
(二)注解实现切面类。
<span style="font-size:18px;">package main.java.com.spring.aop.apj; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.springframework.stereotype.Component; @Component//让spring管理bean @Aspect//定义切面类 public class AnnotationAspectAdvice { /* * 指定切入点匹配表达式,注意它是以方法的形式进行声明的。 * 分析: * execution 是方法的织入语言 * 第一个 * :返回任意类型 * main.java.com.spring.aop.service: 包。 * ..:service包以及其子包。 * 第二个 * :service包以及其子包下的任意类。 * 第三个 * :service包以及其子包下的任意类的任意方法。 * (..) :方法的参数为任意。 * 总结:对 main.java.com.spring.aop.service包以及其子包下的任意类的任意方法作切入 */ @Pointcut("execution(* main.java.com.spring.aop.service..*.*(..))") public void anyMethod() { } /** * 前置通知 * * @param jp */ @Before(value = "execution(* main.java.com.spring.aop.service..*.*(..))") public void doBefore(JoinPoint jp) { System.out.println("===========进入before advice============ \n"); System.out.print("准备在" + jp.getTarget().getClass() + "对象上用"); System.out.print(jp.getSignature().getName() + "方法进行对 '"); System.out.print(jp.getArgs()[0] + "'进行删除!\n\n"); System.out.println("要进入切入点方法了 \n"); } /** * 后置通知 * * @param jp * 连接点 * @param result * 返回值 */ @AfterReturning(value = "anyMethod()", returning = "result") public void doAfter(JoinPoint jp, String result) { System.out.println("==========进入after advice=========== \n"); System.out.println("切入点方法执行完了 \n"); System.out.print(jp.getArgs()[0] + "在"); System.out.print(jp.getTarget().getClass() + "对象上被"); System.out.print(jp.getSignature().getName() + "方法删除了"); System.out.print("只留下:" + result + "\n\n"); } /** * 环绕通知 * * @param pjp * 连接点 */ @Around(value = "execution(* main.java.com.spring.aop.service..*.*(..))") public void doAround(ProceedingJoinPoint pjp) throws Throwable { System.out.println("===========进入around环绕方法!=========== \n"); // 调用目标方法之前执行的动作 System.out.println("调用方法之前: 执行!\n"); // 调用方法的参数 Object[] args = pjp.getArgs(); // 调用的方法名 String method = pjp.getSignature().getName(); // 获取目标对象 Object target = pjp.getTarget(); // 执行完方法的返回值:调用proceed()方法,就会触发切入点方法执行 Object result = pjp.proceed(); System.out.println("输出:" + args[0] + ";" + method + ";" + target + ";" + result + "\n"); System.out.println("调用方法结束:之后执行!\n"); } /** * 异常通知 * * @param jp * @param e */ @AfterThrowing(value = "execution(* main.java.com.spring.aop.service.*.*(..))", throwing = "e") public void doThrow(JoinPoint jp, Throwable e) { System.out.println("删除出错啦"); } } </span>
1)getArgs():获取方法参数。
2)getTarget():得到目标对象。
3)getSignature():得到方法。
2、ProceedingJoinPoint:环绕方法的使用。
1)proceed():执行目标对象的方法。
3、Throwable:异常获取。
标签:spring aop aspectj joinpoint proceedingjoinpoint
原文地址:http://blog.csdn.net/u012228718/article/details/42750083