设计模式——代理模式
来源:互联网 发布:java相关文献 编辑:程序博客网 时间:2024/06/17 20:53
代理模式
名词解释(百度百科):
代理模式:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
抽象角色:通过接口或抽象类声明真实角色实现的业务方法。
真实角色:实现抽象角色(jdk代理),定义真实角色所要实现的业务逻辑,供代理角色调用。
代理角色:实现抽象角色(jdk代理),是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作。
对这些名词有一定概念之后继续阅读可以深入理解代理模式。
代理又分为静态代理和动态代理
我们先从静态代理开始了解代理模式的工作流程
静态代理
抽象角色
java代码:
/** * 抽象角色 * * @author Javen * */public interface UserService { /** * * @Description:测试方法 * @param * @throws */ public void getName();}
真实角色
java代码:
/** * jdk动态代理——被代理类 * * @author Javen * */public class UserServiceImpl implements UserService { @Override public void getName() { System.out.println("---------getName()----------"); }}
代理角色
java代码:
/** * 静态代理——代理角色 * * @author Javen * */public class ProxyUserService implements UserService { private UserServiceImpl userServiceImpl; // 以真实角色作为代理角色的属性 public ProxyUserService() {} public void getName() { // 该方法封装了真实对象的getName方法 beforeGetName();// 真实对象方法执行之前的操作 if (userServiceImpl == null) { userServiceImpl = new UserServiceImpl(); } userServiceImpl.getName(); // 此处执行真实对象的getName方法 afterGetName();// 真实对象方法执行之后的操作 } private void beforeGetName() { // 插入真实对象执行前的操作
System.out.println("---------beforeGetName()----------"); } private void afterGetName() { // 插入真实对象执行后的操作
System.out.println("---------afterGetName()----------"); }}
客户端测试类
java代码:
/** * 静态代理测试类 * * @author Javen * */public class StaticProxyTest { public static void main(String[] args) { UserService userService = new ProxyUserService(); userService.getName(); }}
输出结果:
---------beforeGetName()-------------------getName()-------------------afterGetName()----------
由以上代码可以看出,原本由真实角色UserService执行的getName()方法,现在由代理角色ProxyUserService执行,而且还封装了beforeGetName()和afterGetName()方法,在真实角色执行方法前后加入自定义功能。但是也能看出这种代理模式需要一个真实角色对应一个代理角色,在实际开发中,大量使用静态代理会导致类的急剧增加,所以这时候就需要使用动态代理了,在运行时动态创建代理角色。
动态代理
抽象角色和真实角色沿用上面的代码。
代理角色
java代码:
/** * 动态代理类 * * @author Javen * */public class MyInvocationHandler implements InvocationHandler { private Object target; MyInvocationHandler(Object target) { super(); this.target = target; } /** * * @Title: 调用方法之前的操作 * @Description: * @param * @throws */ public void doBefore() { System.out.println("---------doBefore()----------"); } /** * * @Title: 调用方法之后的操作 * @Description: * @param * @throws */ public void doAfter() { System.out.println("---------doAfter()----------"); } @Override public Object invoke(Object obj, Method method, Object[] args) throws Throwable { doBefore(); Object result = method.invoke(target, args); doAfter(); return result; }}
代理角色有真实角色属性,构造方法;实现InvocationHandler接口,实现invoke(Object obj, Method method, Object[] args)方法,第一个参数obj一般是指代理类,method是被代理的方法,如上例中的getName(),args为该方法的参数数组。这个抽象方法在代理类中动态实现。
客户端测试类
java代码:
/** * 动态代理测试类 * * @author Javen * */public class ProxyMain { public static void main(String[] args) { UserService userService = new UserServiceImpl(); MyInvocationHandler myInvocationHandler = new MyInvocationHandler(userService); UserService userServiceProxy = (UserService) Proxy.newProxyInstance(userService.getClass().getClassLoader(), userService.getClass().getInterfaces(), myInvocationHandler); userServiceProxy.getName(); }}
Proxy代理类有静态方法:Static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler invocationHandler):返回代理类的一个实例,返回后的代理类可以被当作真实角色使用,可使用真实角色中申明的方法。
其实动态代理就是在运行时,通过指定需要实现的接口,然后生成class文件,将该class文件的实例自然就能指向为任意一个已实现的接口,相当于生成了一个代理类实例,但是这个代理类的具体操作封装在InvocationHandler的invoke(Object obj, Method method, Object[] args)中实现,所以在生成代理类的时候还需提供一个handler,由它接管实际操作。
通过这种方式,抽象角色、真实角色都能在运行时动态改变,从而实现了非常灵活的动态代理关系。
补充:
动态代理又分为JDK动态代理和CGLIB动态代理,JDK的动态代理机制只能代理实现了接口的类,而不能实现接口的类就不能实现JDK的动态代理,CGLIB是针对类来实现代理的,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。
Spring是依靠什么来判断采用哪种代理策略来生成AOP代理呢?以下代码就是Spring的判断逻辑
//org.springframework.aop.framework.DefaultAopProxyFactory
//参数AdvisedSupport 是Spring AOP配置相关类
public AopProxy createAopProxy(AdvisedSupport advisedSupport)
throws AopConfigException {
//在此判断使用JDK动态代理还是CGLIB代理
if (advisedSupport.isOptimize() || advisedSupport.isProxyTargetClass()
|| hasNoUserSuppliedProxyInterfaces(advisedSupport)) {
if (!cglibAvailable) {
throw new AopConfigException(
"Cannot proxy target class because CGLIB2 is not available. "
+ "Add CGLIB to the class path or specify proxy interfaces.");
}
return CglibProxyFactory.createCglibProxy(advisedSupport);
} else {
return new JdkDynamicAopProxy(advisedSupport);
}
}
//org.springframework.aop.framework.DefaultAopProxyFactory
//参数AdvisedSupport 是Spring AOP配置相关类
public AopProxy createAopProxy(AdvisedSupport advisedSupport)
throws AopConfigException {
//在此判断使用JDK动态代理还是CGLIB代理
if (advisedSupport.isOptimize() || advisedSupport.isProxyTargetClass()
|| hasNoUserSuppliedProxyInterfaces(advisedSupport)) {
if (!cglibAvailable) {
throw new AopConfigException(
"Cannot proxy target class because CGLIB2 is not available. "
+ "Add CGLIB to the class path or specify proxy interfaces.");
}
return CglibProxyFactory.createCglibProxy(advisedSupport);
} else {
return new JdkDynamicAopProxy(advisedSupport);
}
}
advisedSupport.isOptimize()与advisedSupport.isProxyTargetClass()默认返回都是false,所以在默认情况下目标对象有没有实现接口决定着Spring采取的策略,如果目标对象没有实现接口,则默认会采用CGLIB代理;如果目标对象实现了接口,可以强制使用CGLIB实现代理(添加CGLIB库,并在spring配置中加入<aop:aspectj-autoproxy proxy-target-class="true"/>)。
应用场景:
SpringAop,日志处理等。
阅读全文
1 0
- 设计模式—代理模式
- 设计模式—代理模式
- 设计模式—代理模式
- 设计模式—代理模式
- 设计模式—代理模式
- 设计模式—代理模式
- 设计模式—代理模式
- 设计模式—代理模式
- 设计模式—代理模式
- 设计模式—代理模式
- 设计模式——代理设计模式
- 设计模式——代理设计模式
- 每日设计模式——代理模式
- 学习设计模式——代理模式
- java设计模式——代理模式
- 设计模式——策略、代理模式
- 设计模式——代理模式(Proxy)
- 设计模式——代理模式
- linux下ftp命令调用外部变量传送文件
- javawebday10(xpath查询节点 dom4j crud)
- 设计模式之观察者模式Observer
- android 屏幕适配方案第二版
- 《Hibernate学习笔记三》:联合主键的映射
- 设计模式——代理模式
- TypeError: object() takes no parameters
- 高德地图基本显示
- Kafka学习整理三(borker(0.9.0及0.10.0)配置)
- 本地方法栈及native方法
- 嵌入式Linux初始化QAT失败 及 问题 解决
- 微信开发最重要的一步(服务器配置)
- 侧滑
- ServercnxnFactory启动