7.Spring AOP动态代理
来源:互联网 发布:翻墙推荐 知乎 编辑:程序博客网 时间:2024/04/30 17:04
一.AOP(面向切面编程)中的概念
Aspect(切面):指横切性关注点的抽象即为切面,它与类相似,只是两者的关注点不一样
类是对物体特征的抽象,而切面横切性关注点的抽象.
joinpoint(连接点):所谓连接点是指那些被拦截到的点。在spring中,这些点指的是方
法,因为spring只支持方法类型的连接点,实际上joinpoint还可
以是field或类构造器)
Pointcut(切入点):所谓切入点是指我们要对那些joinpoint进行拦截的定义.
Advice(通知):所谓通知是指拦截到joinpoint之后所要做的事情就是通知.通知分为前置
通知,后置通知,异常通知,最终通知,环绕通知
Target(目标对象):代理的目标对象
Weave(织入):指将aspects应用到target对象并导致proxy对象创建的过程称为织入.
Introduction(引入):在不修改类代码的前提下,Introduction可以在运行期为类动态地
添加一些方法或Field.
二.实现AOP
<?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:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd"> <!-- 配置AOP 注解方式 --> <aop:aspectj-autoproxy></aop:aspectj-autoproxy> <context:component-scan base-package="com.zyy.service"></context:component-scan> <context:component-scan base-package="com.zyy.aop"></context:component-scan></beans>
代理对象:
package com.zyy.service;/** * Created by CaMnter on 2014/8/20. */public interface PersonService_5 { String user = null; public void save(String name); public void update(Integer personId, String name); public void delete(Integer personId); public String getName(); public String getUser();}
SpringAOP设计:
package com.zyy.aop;import com.zyy.service.PersonService_5;import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.annotation.*;import org.springframework.stereotype.Service;/** * Created by CaMnter on 2014/8/21. *//** * 切面 使用注解 * <p/> * 必须交给Spring容器管理 *//* * @Aspect (切面) 声明切面 * * @Pointcut 声明切入点 * * @Pointcut("execution(* com.zyy.service.impl.PersonServiceBean_5.*(..))") * 当执行com.zyy.service.impl.PersonServiceBean_5类下所有方法的时候就会被拦截到 * * @Before("anyMethod()") 前置通知 这里表示在执行anyMethod方法前先执行doBefore * * @AfterReturning("anyMethod()") 后置通知 这里表示在执行anyMethod方法后先执行doAfterReturning * * @After("anyMethod()") 最后通知 无论怎样 最后都执行的 * * @AfterThrowing("anyMethod()") 出现异常的时候的通知 * * @Around("anyMethod()") 环绕通知 (应用比较多) 适合做权限 * 注意:如果使用了环绕通知 就一定要执行 pjp.proceed(); 否则业务Bean中拦截的 Before...等方法不会执行 * * * @Before("anyMethod() && args(name)") 表示 在切入点 * @Pointcut("execution(* com.zyy.service.impl.PersonServiceBean_5.*(..))")的情况下 * 还要求改切入点类的方法只有有一个是String类型 返回给doBefore 作为参数 * * * @AfterReturning(pointcut = "anyMethod()", returning = "user") 表示 在切入点 * @Pointcut("execution(* com.zyy.service.impl.PersonServiceBean_5.*(..))")的情况下 * 还要求改切入点类的方法返回一个String的时候 返回给doAfterReturning 作为参数 * */@Aspect@Service("springInterceptor")public class SpringInterceptor { //@Pointcut("execution(* com.zyy.service.impl.PersonServiceBean_5.*(..))") /* * 切入点是 PersonService_5接口 */ @Pointcut("execution(* com.zyy.service.PersonService_5.*(..))") //定一个切入点 private void anyMethod() { } /* * @Before("anyMethod() && args(name)") 表示 在切入点 * @Pointcut("execution(* com.zyy.service.impl.PersonServiceBean_5.*(..))")的情况下 * 还要求改切入点类的方法只有有一个是String类型 返回给doBefore 作为参数 */ @Before("anyMethod() && args(xxx)") public void doBefore(String xxx) { System.out.println("***** SpringInterceptor 前置通知 " + xxx + " *****"); } /* * @AfterReturning(pointcut = "anyMethod()", returning = "user") 表示 在切入点 * @Pointcut("execution(* com.zyy.service.impl.PersonServiceBean_5.*(..))")的情况下 * 还要求改切入点类的方法返回一个String的时候 返回给doAfterReturning 作为参数 */ @AfterReturning(pointcut = "anyMethod()", returning = "user") public void doAfterReturning(String user) { System.out.println("***** SpringInterceptor 后置通知 " + user + " *****"); } @After("anyMethod()") public void doAfter() { System.out.println("***** SpringInterceptor 最终通知 *****"); } @AfterThrowing(pointcut = "anyMethod()", throwing = "e") public void doAfterThrowing(Exception e) { System.out.println("***** SpringInterceptor (异常)通知 " + e + " *****"); } /* * @Around("anyMethod()") 环绕通知 (应用比较多) 适合做权限 * 注意:如果使用了环绕通知 就一定要执行 pjp.proceed(); 否则业务Bean中拦截的 Before...等方法不会执行 */ @Around("anyMethod()") public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable { //因为我们已知切入点@Pointcut("execution(* com.zyy.service.PersonService_5.*(..))") //所以可以得到代理对象 PersonService_5 personService_5 = (PersonService_5) pjp.getTarget(); Object result = null; //权限过滤 如果有user值 if (!(personService_5.getUser() == null || "".equals(personService_5.getUser()))) { System.out.println("***** SpringInterceptor (进入)环绕通知 *****"); System.out.println("***** 代理对象有user值,允许调用save *****"); //如果不执行这个方法,那么代理对象的方法也不执行了 result = pjp.proceed(); System.out.println("***** SpringInterceptor (退出)环绕通知 *****"); return result; } System.out.println("***** 代理对象无user值,不允许调用 *****"); return result; }}
代理对象实现bean:
有user值的bean:
package com.zyy.service.impl;/** * Created by CaMnter on 2014/8/21. */import com.zyy.service.PersonService_5;import org.springframework.stereotype.Service;/** * 实现Spring AOP * * 有user值 */@Service("personService_5")public class PersonServiceBean_5 implements PersonService_5 { private String user = "CaMnter"; public PersonServiceBean_5() { } public PersonServiceBean_5(String user) { this.user = user; } public void save(String name) { System.out.println("***** save " + name + " *****"); //throw new RuntimeException("Remember") ; } public void update(Integer personId, String name) { System.out.println("***** update *****"); } public void delete(Integer personId) { System.out.println("***** delete *****"); } public String getName() { return "Save you from anything 07"; } public String getUser() { return user; } public void setUser(String user) { this.user = user; }}
无user值的bean:
package com.zyy.service.impl;/** * Created by CaMnter on 2014/8/21. */import com.zyy.service.PersonService_5;import org.springframework.stereotype.Service;/** * 实现Spring AOP * * 无user值 */@Service("personService_7")public class PersonServiceBean_7 implements PersonService_5 { private String user = null; public PersonServiceBean_7() { } public PersonServiceBean_7(String user) { this.user = user; } public void save(String name) { System.out.println("***** save " + name + " *****"); //throw new RuntimeException("Remember") ; } public void update(Integer personId, String name) { System.out.println("***** update *****"); } public void delete(Integer personId) { System.out.println("***** delete *****"); } public String getName() { return "Save you from anything 07"; } public String getUser() { return user; } public void setUser(String user) { this.user = user; }}
junit4.4测试代码:
有user值的测试:
@Test public void springAopTest_1() { AbstractApplicationContext abstractApplicationContext = new ClassPathXmlApplicationContext("beans_3.xml"); System.out.println("***** SpringAOP动态代理 *****"); System.out.println("***** 动态代理对象有user值 *****"); System.out.println(""); System.out.println("***** 调用save()并且有参数String类型 *****"); PersonService_5 personService_5 = (PersonService_5) abstractApplicationContext.getBean("personService_5"); personService_5.save("07"); System.out.println(""); System.out.println("***** getName()返回String类型 *****"); personService_5 = (PersonService_5) abstractApplicationContext.getBean("personService_5"); personService_5.getName(); }
无user值的测试:
@Test public void springAopTest_2() { AbstractApplicationContext abstractApplicationContext = new ClassPathXmlApplicationContext("beans_3.xml"); System.out.println("***** SpringAOP动态代理 *****"); System.out.println("***** 动态代理对象无user值 *****"); System.out.println(""); System.out.println("***** 调用save()并且有参数String类型 *****"); PersonService_5 personService_5 = (PersonService_5) abstractApplicationContext.getBean("personService_7"); personService_5.save("07"); System.out.println(""); System.out.println("***** 调用save()返回String类型 *****"); personService_5 = (PersonService_5) abstractApplicationContext.getBean("personService_7"); personService_5.getName(); }
由此可见,SpringAOP动态代理足够强大。其原理也是很简单:如果目标有接口那么
SpringAOP调用的是JDK动态代理,如果没接口SpringAOP调用用的是CGlib动态
代理,这就导致了为什么cglib-nodep.jar出现在Spring 的依赖包之中。
三.aspectj的切入点语法定义细节
@Pointcut("execution(java.lang.Stringcom.zyy.service.PersonService_5.*(..))")
拦截返回String的方法
@Pointcut("execution(* com.zyy.service.PersonService_5.*(java.lang.String,..))")
拦截第一个的参数为String类型的方法
@Pointcut("execution(!void com.zyy.service.PersonService_5.*(java.lang.String,..))")
拦截非void返回值的方法
@Pointcut("execution(java.lang.Stringcom.zyy.service.*.*(..))")
拦截com.zyy.service子包内所有的类的所有方法
@Pointcut("execution(java.lang.Stringcom.zyy.service.*.s*(..))")
拦截以s开头的方法
- 7.Spring AOP动态代理
- Spring Aop 动态代理
- Spring AOP动态代理
- Spring AOP 动态代理
- spring aop动态代理
- Spring(AOP动态代理)
- Spring AOP配置 动态代理
- Spring AOP JDK动态代理
- 动态代理与spring AOP
- Spring AOP与动态代理
- Spring AOP动态代理初学
- Spring AOP技术--动态代理
- Java动态代理-->Spring AOP
- spring AOP(动态代理)解析
- spring aop,java动态代理
- Spring中AOP动态代理
- 动态代理实现Spring Aop
- 【spring 4】AOP:动态代理
- ORACLE函数大全
- 从Access中创建Sqlite数据库
- Android 显示CMKY颜色
- RO段、RW段和ZI段 --Image$$??$$Limit 含义(zz)
- CentOS分区方案
- 7.Spring AOP动态代理
- 数组的指针特性
- UrlRewriteFilter 学习笔记
- 锅炉产业升级新标实施需配套手段跟进
- [转]关于ffmpeg 的总结(一个linux 下 集 屏幕录像录音,音频视频转换,合并音频视频文件,格式转换于一身的命令)
- java 设置环境变量
- valgrind+kcachegrind分析程序性能瓶颈
- cocos2d-x 3.0rc开发指南:Windows下Android环境搭建
- linux centos 下安装yii