-- 存在代理对象和被代理对象,顾名思义,代理对象可以为其它对象提供一中代理(Proxy)以控制其它对这个对象的访问(或是对这个对象的 拦截)
一、模式结构
组成(角色) | 关系 | 作用 |
---|---|---|
抽象主题角色(Subject) | 真实与代理的共同接口 | 提供抽象方法的中间件 |
真实主题角色 (Real) | 抽象主题实现类 | 定义将要被代理的真实主题角色 |
代理主题角色 (Proxy) | 抽象主题实现类 | 含有对真实主题角色的引用,并代理真实主题角色 |
1、静态代理 -- 执行前已经编译好了,并没有在内存中构建或是动态编译。
(1)、抽象主题角色
package com.construction.proxy.staticProxy;
/**
* @description: 代理中间主题
* @author: ziHeng
* @create: 2018-08-07 18:25
**/
public interface Subject {
void deal();
}
(2)、真实主题角色 - 被代理对象
package com.construction.proxy.staticProxy;
/**
* @description: 商店
* @author: ziHeng
* @create: 2018-08-07 18:27
**/
public class OriginShop implements Subject{
@Override
public void deal() {
System.out.println("原始商店处理");
}
}
(3)、代理主题角色
package com.construction.proxy.staticProxy;
/**
* @description: 代理商店
* @author: ziHeng
* @create: 2018-08-07 18:30
**/
public class ProxyShop implements Subject {
//对真实主题的引用
private Subject originSubject;
public ProxyShop(Subject originSubject) {
this.originSubject = originSubject;
}
@Override
public void deal() {
System.out.println("原始商店处理");
originSubject.deal();
System.out.println("代理商店处理");
}
}
2、动态代理
-- jdk 的InvocationHandler实现方式
(1)、抽象主题角色
package com.construction.proxy.dynamicProxy;
/**
* @description: 中间方法
* @author: ziHeng
* @create: 2018-08-07 22:10
**/
public interface Subject {
void deal();
}
(2)、真实主题角色 - 被代理对象
package com.construction.proxy.dynamicProxy;
/**
* @description:
* @author: ziHeng
* @create: 2018-08-07 22:11
**/
public class OriginHandler implements Subject{
@Override
public void deal() {
System.out.println("原始处理");
}
}
(3)、代理主题角色 - 实现 InvocationHandler
package com.construction.proxy.dynamicProxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* @description: jdk代理处理
* @author: ziHeng
* @create: 2018-08-07 22:06
**/
public class ProxyHandler implements InvocationHandler {
private Subject originHandler;
public ProxyHandler(Subject originHandler) {
this.originHandler = originHandler;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//原始处理
//originHandler.deal();
System.out.println("当前代理的方法名:"+method.getName());
method.invoke(originHandler,args);
System.out.println("代理后处理:"+method);
return null;
}
}
测试类:
public class DynamicProxyTest {
public static void main(String[] args) {
Subject originHandler = new OriginHandler();
//取被代理对象的 Class类
Class originHandlerClass = originHandler.getClass();
//Jdk 动态创建代理实例
Subject proxyInstance = (Subject)Proxy.newProxyInstance(originHandlerClass.getClassLoader(), originHandlerClass.getInterfaces(), new ProxyHandler(originHandler));
//代理对象处理
proxyInstance.deal();
//打印代理对象Class类名 - 突然对其原理产生兴趣
System.out.println(proxyInstance.getClass().getName());
}
}
newProxyInstance原理传送门:
- 从代理模式再出发!Proxy.newProxyInstance的秘密_葵续浅笑的博客-CSDN博客
- https://bbs.csdn.net/topics/390346645
- 动态代理(3)- newProxyInstance()实现原理_newproxyinstance原理_多态的博客-CSDN博客
传送门文章总结:
- newProxyInstance生成新的接口实例前,进行了验证、优化、缓存、同步生成字节码和显示类加载操作,而最后调用了
sun.misc.ProxyGenerator.generateProxyClass()方法完成字节码的动作,这个方法可以在运行时产生描述一个代理类的字节码byte[]
的数组
-
generateProxyClass()方法 大概就是根据Class文件的格式规范去拼装字节码,但是在实际开发中,以byte为单位直接拼装出字节码的应用场合很少见,这种生成方式只能产生一些高度模板化的代码。对于用户的程序代码来说,如果有大量操作字节码的需求,还是使用封装好的字节码类库比较合适。
-
这段可以在磁盘中生成编译后的代理类(生成路径:项目根目录/com/sum/proxy),通过反编译(有的编译器会帮你反编译,例如:Intellj idea)可以代理类的真面目
public static void main(String[] args) {
//这段可以在磁盘中生成编译后的代理类,通过反编译可以代理类的真面目
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");
}
-- Cglib实现方式(较优)
优点:
- 针对指定类实现代理(不需要定义抽象主题角色),也是用反射生成被代理类的子类。
- 避免根据抽象主题角色接口的方法修改,进而牵动到真实主题角色和代理主题角色的修改
Maven依赖:
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib-nodep</artifactId>
<version>3.1</version>
</dependency>
(1)、真实角色
package com.construction.proxy.cglib;
/**
* @description: 商店
* @author: ziHeng
* @create: 2018-08-09 14:31
**/
public class Shop {
public void deal(){
System.out.println("原始商店");
}
}
(2)、代理角色
package com.construction.proxy.cglib;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
* @description: 商店代理
* @author: ziHeng
* @create: 2018-08-09 14:31
**/
public class ShopProxy implements MethodInterceptor {
//通过Enhancer 创建代理对象
private Enhancer enhancer = new Enhancer();
//传入代理对象类并返回其子类(被代理对象的子类)
public Object getProxy(Class c){
//必须 传入需要被代理对象
enhancer.setSuperclass(c);
//必须 传入代理对象
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object obj, Method m, Object[] args, MethodProxy proxy) throws Throwable {
//代理类调用父类的方法
proxy.invokeSuper(obj, args);
return null;
}
}
调用Test类:
package com.construction.proxy.cglib;
/**
* @description: 测试
* @author: ziHeng
* @create: 2018-08-09 14:34
**/
public class TestCgib {
public static void main(String[] args) {
//创建我们的代理类
ShopProxy Proxy = new ShopProxy();
//获取代理对象
Shop shop = (Shop)Proxy.getProxy(Shop.class);
shop.deal();
}
}
-- SpringAop实现方式 (框架最优)
- 如果是集成spring框架的项目一般都使用这个
这里先贴出aop官方文档: