Spring - 动态代理 与 AOP 理解
2015-12-29 15:46
549 查看
一.动态代理模式
(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 {
@Override
public 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();
}
@Override
public 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)测试
@Test
public 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{
@Override
public void intercepterCheck() {
System.out.println("Log 已记录");
}
}
3)安全监测类
public class SafeCheck implements Intercepter{
@Override
public 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;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
for (Intercepter intercepter : intercepters) {
intercepter.intercepterCheck();
}
method.invoke(target, args);
return null;
}
}
6).测试
@Test
public 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("安全性检测");
}
}
4)dao层实现
接口:
public interface SalaryManager {
void selectSalary();
}
接口实现:
public class SalaryManagerImp implements SalaryManager {
@Override
public 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相关文章推荐
- yui3的AOP(面向切面编程)和OOP(面向对象编程)
- extjs 为某个事件设置拦截器
- 动态代理的5模式使用示例和Mixin模式
- JavaScript AOP编程实例
- 使用AOP改善javascript代码
- 初识SmartJS - AOP三剑客
- 浅析JAVA中过滤器、监听器、拦截器的区别
- java实现动态代理示例分享
- java使用动态代理来实现AOP(日志记录)的实例代码
- java利用反射实现动态代理示例
- Java实现动态代理
- java自定义拦截器用法实例
- java动态代理和cglib动态代理示例分享
- JavaScript之AOP编程实例
- PHP的cURL库简介及使用示例
- SQL Server中通配符的使用示例
- PHP的拦截器实例分析
- Javascript aop(面向切面编程)之around(环绕)分析
- php笔记之:AOP的应用
- Java远程过程调用基础:构建可自适应的动态代理对象的通用方法