Spring - 动态代理 与 AOP 理解
来源:互联网 发布:windows自带画图工具 编辑:程序博客网 时间:2024/05/25 18:09
一.动态代理模式
(1)产生的代理对象和目标对象实现了共同的接口;(jdk动态代理)
JDK的动态代理 :1. 用Jdk的API做到的;
2. 代理对象时动态产生的;
注意:
1. 拦截器中invoke方法体的内容就是代理对象方法体的内容;
2. 当客户端执行代理对象,方法的时候,进入到了拦截器的invoke的方法体内;
3. 拦截器invoke方法中的method参数是在调用的时候赋值操作;
具体理解: http://blog.csdn.net/lablenet/article/details/50419811
(2)代理对象时目标对象的子类;(spring:cglib动态代理)
cglib产生的代理类是目标类的子类;
springAop工具包下载: http://download.csdn.net/detail/lablenet/9382210
(3)示例说明cglib动态代理
1)场景描述
假设你正在进行一个查询系统中薪资的判断,故需要进行日志记录,安全监测,权限判断,后输出查询结果;
UML图:
2)日志记录类
public class Logging {public void pringlnLog(){System.out.println("Log 已记录");}}
3)安全监测类
public class SafeCheck {public void safeCheckPrint(){System.out.println("安全性检测");}}
4)权限类
public class AdminCheck {private String access;public String getAccess() {return access;}public void setAccess(String access) {this.access = access;}public void adminCheckPrint(){System.out.println("权限检测");}}
5)dao层
public interface SalaryManager { void selectSalary();}
实现类:
public class SalaryManagerImp implements SalaryManager {@Overridepublic void selectSalary() {System.out.println("薪资10000");}}
6)拦截器
public class SalaryIntercepter implements MethodInterceptor{//目标类private Object target;//日志记录private Logging logging;//安全性检测private SafeCheck safeCheck;//权限检测private AdminCheck adminCheck;public SalaryIntercepter(Object target, Logging logging,SafeCheck safeCheck, AdminCheck adminCheck) {super();this.target = target;this.logging = logging;this.safeCheck = safeCheck;this.adminCheck = adminCheck;}public Object createProxy(){ Enhancer enhancer=new Enhancer(); enhancer.setCallback(this); enhancer.setSuperclass(this.target.getClass()); return enhancer.create(); }@Overridepublic Object intercept(Object arg0, Method arg1, Object[] arg2,MethodProxy arg3) throws Throwable {logging.pringlnLog();safeCheck.safeCheckPrint();if(adminCheck.getAccess().equals("admin")){arg1.invoke(target, arg2);}else{System.out.println("你没有权限");}return null;}}
7)测试
@Testpublic void testSalaryIntercepter() {AdminCheck adminCheck = new AdminCheck();adminCheck.setAccess("admin");Logging logging = new Logging();SafeCheck safeCheck = new SafeCheck();Object target = new SalaryManagerImp();SalaryIntercepter intercepter = new SalaryIntercepter(target, logging,safeCheck, adminCheck);SalaryManager manager = (SalaryManager) intercepter.createProxy();manager.selectSalary();}
(4)重构
在这里如果我们想要加上某个功能来监测,故我们进行拦截器重构实现;
基本思路是: 1)提供一个监测接口,使得日志,安全,权限,都实现该接口,使用List进行重构实现;
UML图 :
1)监测接口
public interface Intercepter {void intercepterCheck();}
2)日志记录类
public class Logging implements Intercepter{@Overridepublic void intercepterCheck() {System.out.println("Log 已记录");}}
3)安全监测类
public class SafeCheck implements Intercepter{@Overridepublic void intercepterCheck() {System.out.println("安全性检测");}}
4)dao层不变
5)拦截器实现
public class SalaryIntercepter implements InvocationHandler {// 目标类private Object target;private List<Intercepter> intercepters;// //日志记录// private Logging logging;// //安全性检测// private SafeCheck safeCheck;// //权限检测// private AdminCheck adminCheck;public SalaryIntercepter(Object target, List<Intercepter> intercepters) {super();this.target = target;this.intercepters = intercepters;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args)throws Throwable {for (Intercepter intercepter : intercepters) {intercepter.intercepterCheck();}method.invoke(target, args);return null;}}
6).测试
@Testpublic void testSalaryIntercepter(){AdminCheck adminCheck=new AdminCheck();adminCheck.setAccess("admin");Logging logging = new Logging();SafeCheck safeCheck = new SafeCheck();Object target = new SalaryManagerImp();List<Intercepter> intercepters=new ArrayList<Intercepter>();intercepters.add(safeCheck);intercepters.add(adminCheck);intercepters.add(logging);SalaryIntercepter intercepter = new SalaryIntercepter(target, intercepters);SalaryManager salaryManager = (SalaryManager) Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),intercepter);salaryManager.selectSalary();}
二 .Aop
(1).切面
事务,日志,安全性框架,权限等都是切面,非目标类的都是切面;(2).通知
切面中的方法就是通知;(3).目标类
(4).切入点
只有符合切入点,才能让通知和目标方法结合起来;
(5).织入
形成代理对象的方法的过程; 好处:事务,日志,安全性框架,权限,目标方法之间完全是松耦合的;
使用:找目标类及其找目标类的切面;
(6) 具体价值步骤
1)当spring容器启动的时候,加载了spring的配置文件;2)未配置文件中所有的类创建对象;
3)spring容器解析aop:config的配置:解析切入点表达式,用切入点表达式纳入spring容器中的bean匹配;
如果成功,则会位该bean创建代理对象,代理对象的方法=目标方法+通知
4)在客户端利用context.getbean获取对象的时候,如果有代理对象,则返回代理对象;
5)如果目标类没有实现接口,则spring容器采用cglib的方式产生代理对象,否则采用jdk的代理对象;
<aop:config> <aop:pointcut expression="execution(* cn.labelnet.salary.SalaryManagerImp.*())" id="pointsalary"/> <aop:aspect ref="logging"> <aop:before method="pringlnLog" pointcut-ref="pointsalary"/> </aop:aspect> <aop:aspect ref="adminCheck"> <aop:around method="isAdmin" arg-names="point" pointcut-ref="pointsalary"/> </aop:aspect> <aop:aspect ref="safeCheck"> <aop:before method="safeCheckPrint" pointcut-ref="pointsalary"/> </aop:aspect> </aop:config>
(7)各种通知
1)前置通知(aop:before)在目标方法执行之前执行,无论目标方法是否抛出异常,都执行,因为在执行前置通知的时候,目标方法还没有执行,还没有遇到异常;
<aop:before method="pringlnLog" pointcut-ref="pointsalary"/>
2)后置通知(aop:after-returning)
在目标方法之后执行,当目标方法遇到异常,后置通知不执行;后置通知可以接受目标方法的参数var,但是需要注意,后置通知的参数名称和配置文件中的returning="var"的值是一致的;
3)最终通知(aop:after)
在目标方法执行之后执行,无论目标方法是否跑出异常,都执行,因为相当于finally;
4)异常通知(aop:after-throwing)
接收的目标方法和抛出的异常信息,异常方法中的参数th和配置文件中的throwing="th"一致;
5)环绕通知(aop:)
如果不在环绕通知中调用ProceedingJoinoPoint的proceed,目标方法不会执行;可以控制目标方法的执行;
(8)示例:
场景还是上面的查询薪资;
UML 图 :
1)权限检查
public class AdminCheck {private String access;public String getAccess() {return access;}public void setAccess(String access) {this.access = access;}
//重要 对于配置文件中 aop:round 环绕通知public void isAdmin(ProceedingJoinPoint point) throws Throwable{if(this.access.equals("admin")){point.proceed();}else{System.out.println("sorry,you no 权限");}}}
2)日志记录
public class Logging {public void pringlnLog(){System.out.println("Log 已记录");}}
3)安全监测
public class SafeCheck {public void safeCheckPrint(){System.out.println("安全性检测");}}
接口:
public interface SalaryManager { void selectSalary();}
接口实现:
public class SalaryManagerImp implements SalaryManager {@Overridepublic void selectSalary() {System.out.println("薪资10000");}}
5)配置实现
在上面我们知道使用 Intercepter 拦截器实现,动态代理,在这里我们使用spring配置文件实现:
<?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:aop="http://www.springframework.org/schema/aop" 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 http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd"> <bean id="salaryTarget" class="cn.labelnet.salary.SalaryManagerImp"></bean> <bean id="adminCheck" class="cn.labelnet.salary.AdminCheck"> <property name="access" value="admin"></property> </bean> <bean id="logging" class="cn.labelnet.salary.Logging"></bean> <bean id="safeCheck" class="cn.labelnet.salary.SafeCheck"></bean> <aop:config> <aop:pointcut expression="execution(* cn.labelnet.salary.SalaryManagerImp.*())" id="pointsalary"/> <aop:aspect ref="logging"> <aop:before method="pringlnLog" pointcut-ref="pointsalary"/> </aop:aspect> <aop:aspect ref="adminCheck"> <aop:around method="isAdmin" arg-names="point" pointcut-ref="pointsalary"/> </aop:aspect> <aop:aspect ref="safeCheck"> <aop:before method="safeCheckPrint" pointcut-ref="pointsalary"/> </aop:aspect> </aop:config> </beans>
3.Demo免积分下载
http://download.csdn.net/detail/lablenet/9382126
0 0
- Spring - 动态代理 与 AOP 理解
- spring基础概念AOP与动态代理理解
- 动态代理与spring AOP
- Spring AOP与动态代理
- Spring AOP 静态代理与动态代理
- spring Aop理解 一:jdk 动态代理
- Spring AOP与Java动态代理
- JDK动态代理与Spring AOP
- Spring Aop 动态代理
- Spring AOP动态代理
- Spring AOP 动态代理
- spring aop动态代理
- Spring(AOP动态代理)
- Spring AOP之 java 动态代理(Proxy 与 InvocationHandler)理解
- Spring AOP中的JDK动态代理与CGLIB代理
- JDK动态代理(Spring AOP理解的基础)
- 动态代理与AOP
- 动态代理与AOP
- imp exp
- 用Eclipse浏览Linux Kernel源代码,仿照SourceInsight的颜色配置
- 基于Core Animation的KTV歌词视图的平滑实现
- Git教程
- Git bash常用命令
- Spring - 动态代理 与 AOP 理解
- 用于验证码图片识别的类(C#源码)
- android 实现 搜索保存历史记录功能
- 使用CALayer的Mask实现注水动画效果
- app开发过程中内存泄漏一些简述_懂了这些你的app还在闪退么?
- 文件夹的删除与复制
- linux 使用ls与du查看的大小不一样
- MIMO信道的信道容量
- Socket通信简例