代理模式:为其他的对象提供代理
以控制
这个对象的访问
代理模式的关键点是:代理对象
与目标对象
.代理对象是对目标对象的扩展,并会调用目标对象
.
代理模式的作用:aop实现
、拦截器
、中介、媒婆、解耦、专人做专事
spring的体现: Spring 的 Proxy 模式在 AOP 中有体现
, 比如 JdkDynamicAopProxy
和 Cglib2AopProxy
1.代理模式分类
在介绍分类之前,先了解一下代理模式的UML图
代理模式.png
静态代理的特点:在代理之前,所有的东西都是已知的
(人工)
动态代理的特点:在代理之后,所有的东西都是未知的
(自动化)
一般的实现分为:
静态代理
(目标对象和代理对象实现相同的父类或者接口)动态代理
(具有动态性实现方法调用)
jdk动态代理
(基于接口的形式)
cglib动态代理
(基于继承的形式)
2.静态代理实现
一个人通用的接口
/**
* @Project: spring
* @description: 人的接口
* @author: sunkang
* @create: 2018-08-28 20:49
* @ModificationHistory who when What
**/
public interface Person {
//找对象
void findLove();
}
目标对象
/**
* @Project: spring
* @description: 目标对象
* 男人想找对象
* @author: sunkang
* @create: 2018-08-28 20:54
* @ModificationHistory who when What
**/
public class Man implements Person {
//找对象
@Override
public void findLove() {
System.out.println("我是一个男人,想找一位女朋友");
}
}
静态代理实现 需要实现跟目标对象一样的接口,重写findlove方法完成代理
/**
* @Project: spring
* @description: 静态代理 实现目标对象的代理
* @author: sunkang
* @create: 2018-09-02 22:30
* @ModificationHistory who when What
**/
public class StaticProxy implements Person {
private Person person;
public StaticProxy(Person person) {
this.person = person;
}
public void findLove(){
System.out.println("根据你的要求物色");
this.person.findLove();
System.out.println("双方父母是不是同意");
}
//静态代理测试
public static void main(String[] args) {
StaticProxy staticProxy = new StaticProxy(new Man());
staticProxy.findLove();
}
}
3.jdk动态代理实现
jdk动态代理对象 媒婆
/**
* @Project: spring
* @description: 代理对象 媒婆
* @author: sunkang
* @create: 2018-08-28 20:49
* @ModificationHistory who when What
**/
public class MeiPo implements InvocationHandler {
private Person person;
public Person getInstance(Person person){
this.person = person;
Class clazz = person.getClass();
System.out.println("原有的person的类为:"+clazz.getName());
//基于jdk 中Proxy类用来生成一个新的对象(字节码重组来实现)
return (Person) Proxy.newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(),this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("代理类为:"+proxy.getClass());
System.out.println("我是媒婆");
//这样就会循环触发调用
//method.invoke(proxy,args);
method.invoke(person,args);
System.out.println("正在帮你找");
return null;
}
}
jdk动态方法测试
/**
* @Project: spring
* @description:
* @author: sunkang
* @create: 2018-08-28 20:55
* @ModificationHistory who when What
**/
public class Test {
public static void main(String[] args) {
Person xiaoming = new Man();
Person meipo = new MeiPo().getInstance(xiaoming);
meipo.findLove();
//原理:
//1、拿到被代理对象的引用,并且获取到它的所有的接口,反射获取 (获取接口)
//2、JDK Proxy类重新生成一个新的类、同时新的类要实现被代理类所有实现的所有的接口 (实现接口)
//3、动态生成Java代码,把新加的业务逻辑方法由一定的逻辑代码去调用(在代码中体现)(生成java代码)
//4、编译新生成的Java代码.class (编译)
//5、再重新加载到JVM中运行 (加载)
//这里是接口的代码生成器
byte[] data = ProxyGenerator.generateProxyClass("$Proxy0",new Class[]{Person.class});
try {
//此为jdk 1.7发行的nio的类 作用是把 data 数据写到 文件 $Proxy0.class中
Files.newOutputStream(Paths.get("$Proxy0.class")).write(data);
} catch (IOException e) {
e.printStackTrace();
}
}
}
根据ProxyGenerator 生成代码 如下:
可以发现该动态代理类实现了 Person 的接口
,然后根据接口动态生成了$Proxy0 类,比如当代理对象调用findLove的方法实,由具体的InvocationHandler 进行调用invoke方法,而invoke方法实现了目标的对象的具体调用,从而实现动态调用的作用
。
public final class $Proxy0 extends Proxy implements Person {
private static Method m1;
private static Method m3;
private static Method m2;
private static Method m0;
public $Proxy0(InvocationHandler var1) throws {
super(var1);
}
public final boolean equals(Object var1) throws {
try {
return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final void findLove() throws {
try {
super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final String toString() throws {
try {
return (String)super.h.invoke(this, m2, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final int hashCode() throws {
try {
return (Integer)super.h.invoke(this, m0, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m3 = Class.forName("com.spring.designPattern.proxy.jdk.Person").getMethod("findLove");
m2 = Class.forName("java.lang.Object").getMethod("toString");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
4.cglib动态代理实现
目标对象
/**
* @Project: spring
* @description: cglib 目标对象
* @author: sunkang
* @create: 2018-08-28 22:30
* @ModificationHistory who when What
**/
public class CgMan {
public void findLove() {
System.out.println("我是一个男人,想找一位女朋友");
}
}
cglib动态代理 媒婆对象
/**
* @Project: spring
* @description: cglib动态代理 媒婆
* 需要实现 MethodInterceptor接口
* @author: sunkang
* @create: 2018-08-28 22:31
* @ModificationHistory who when What
**/
public class CgMeiPo implements MethodInterceptor {
public Object getInstance(Class clazz){
Enhancer enhancer = new Enhancer();
//cglib 主要根据继承来生成代码的关系
//设置父类
enhancer.setSuperclass(clazz);
//设置回调 就是代理类通过 MethodInterceptor 找到 intercept方法进行回调
enhancer.setCallback(this);
//crate 方法
//第一步、生成源代码
//第二步、编译成class文件
//第三步、加载到JVM中,并返回被代理对象
return enhancer.create();
}
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("我是媒婆,通过cglib 来实现的");
//这样就会循环触发调用
//cglib的代理实际上原有的对象的子类,通过继承来实现,这里默认调用父类的方法,obj 为cglib代理的子类
//切记不要写成 methodProxy.invoke(obj,args); 这里面就会存在循环调用的问题,这里会调用cglib代理类,然后循环调用
//调用父类
methodProxy.invokeSuper(obj,args);
System.out.println("正在帮你找");
return null;
}
}
cglib动态代理测试类
/**
* @Project: spring
* @description: cglib 动态代理测试类
* @author: sunkang
* @create: 2018-08-28 22:40
* @ModificationHistory who when What
**/
public class CgTest {
public static void main(String[] args) {
CgMan xiaoming = new CgMan();
CgMan cgmeipo = (CgMan) new CgMeiPo().getInstance(xiaoming.getClass());
cgmeipo.findLove();
}
}
5.自定义实现动态代理
思路: 主要根据ProxyGenerator类生成传入的接口的字节码
,然后根据自定义的类加载器加载字节码得到具体的代理类
,通过反射得到代理类的构造方法
,最后通过反射构造新对象返回对象
具体的代码如下:
自定义的Person接口
/**
* @Project: spring
* @description: 自定义的Person接口
* @author: sunkang
* @create: 2018-08-29 21:40
* @ModificationHistory who when What
**/
public interface CuPerson {
void findLove();
}
自定义的目标对象
/**
* @Project: spring
* @description: 自定义的目标对象
* @author: sunkang
* @create: 2018-08-29 21:41
* @ModificationHistory who when What
**/
public class CuMan implements CuPerson {
@Override
public void findLove() {
System.out.println("我是一个男人,想找一位女朋友");
}
}
自定义的媒婆对象
/**
* @Project: spring
* @description: 自定义的媒婆对象
* @author: sunkang
* @create: 2018-08-29 20:33
* @ModificationHistory who when What
**/
public class CuMeipo implements InvocationHandler {
private CuPerson person;
public CuPerson getInstance(CuPerson person){
this.person = person;
Class clazz = person.getClass();
System.out.println("原有的person的类为:"+clazz.getName());
return (CuPerson) CuProxy.newProxyInstance(clazz.getInterfaces(),this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("代理类为:"+proxy.getClass());
System.out.println("我是媒婆");
//这样就会循环触发调用
//method.invoke(proxy,args);
method.invoke(person,args);
System.out.println("正在帮你找");
return null;
}
}
自定义的生成代理类的实现
/**
* @Project: spring
* @description: 自定义的生成代理类的实现
* @author: sunkang
* @create: 2018-08-29 20:19
* @ModificationHistory who when What
**/
public class CuProxy {
public static Object newProxyInstance(
Class<?>[] interfaces,
InvocationHandler h) {
//1.根据接口生成class文件
byte[] bytes = ProxyGenerator.generateProxyClass("$Proxy0", interfaces);
try {
//写入一个文件可以查看生成的源代码
OutputStream os = Files.newOutputStream(Paths.get("$Proxy0.class"));
os.write(bytes);
//2.通过自定义类加载器动态加载代理类
CuClassLoader loader = new CuClassLoader(bytes);
Class proxyClazz = loader.loadClass("$Proxy0");
//3.得到代理类的构造方法
System.out.println(proxyClazz.getName());
Constructor construct = proxyClazz.getConstructor(InvocationHandler.class);
//4.返回代理对象
return construct.newInstance(h);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
自定义的类加载器
/**
* @Project: spring
* @description: 自定义的类加载器
* 要实现 findClass对象 实现自定义类的加载
* 最后通过findclass 的native方法加载返回类
*
* @author: sunkang
* @create: 2018-08-29 20:25
* @ModificationHistory who when What
**/
public class CuClassLoader extends ClassLoader {
private byte[] bytes ;
public CuClassLoader(byte[] bytes) {
this.bytes = bytes;
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
String className = CuClassLoader.class.getPackage().getName() + "." + name;
return defineClass(name,bytes,0,bytes.length);
}
}
自定义的测试方法
/**
* @Project: spring
* @description: 自定义的测试方法
* @author: sunkang
* @create: 2018-08-29 20:33
* @ModificationHistory who when What
**/
public class CuTest {
public static void main(String[] args) {
CuPerson xiaoming = new CuMan();
CuPerson meipo = new CuMeipo().getInstance(xiaoming);
meipo.findLove();
}
}