1、代理模式介绍
代理模式就是调用者直接调用代理类,通过代理类再去调用业务类,最终完成逻辑处理的过程,
代理模式一个主要的功能就是实现延迟加载,加快系统启动速度。
系统初始化时只需要初始化代理类即可,等到真正要处理业务逻辑,代理类才需要初始化业务类,并且调用业务类的对应方法来实现功能,将结果范围给调用方。
代理模式有两种:静态代理和动态代理
-
1、静态代理:
定义一个interface,代理类和业务逻辑实现类都实现这个接口,业务逻辑类是真正实现抽象方法的具体逻辑的,而代理类只是调用业务类的对应方法,并且将结果返回给调用方。缺点:代理类需要实现接口的每一个方法,繁琐
-
2、动态代理:
动态代理就是为了解决上述代理类繁琐的操作的,有几种实现方式。
1:)原生的jdk; 2:)cglib; 3:)javassist; 4:)ASM。 用的比较多的是前面三种,通过代理类,反射调用业务逻辑类的方法可以实现对方法的调用。
2、静态代理
/**
* 静态代理中,代理类和实现类都需要实现相同的接口
* 拥有相同的操作入口,同时可以使用接口作为引用进行操作
*
* [@Author](https://my.oschina.net/arthor) liufu
* @CreateTime 2018/3/23 16:28
*/
public class StaticProxy {
public static void main(String[] args) {
//只是创建代理类,此时不需要创建实现类(构建需要很久)
Person proxy = new ChineseProxy();
proxy.say();
}
interface Person {
void say();
}
static class Chinese implements Person {
public Chinese() {
//模拟大实例类Chinese的构建耗时
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
[@Override](https://my.oschina.net/u/1162528)
public void say() {
System.out.println("im chinese!");
}
}
static class ChineseProxy implements Person {
private Chinese chinese = null;
[@Override](https://my.oschina.net/u/1162528)
public void say() {
// 只有用到的时候再去创建,延迟加载,
// 如果Chinese对象非常大,提高系统启动速度
if (chinese == null) {
chinese = new Chinese();
}
//最后还是调用真正实现类的方法去实现
chinese.say();
}
}
}
3、动态代理
1、java自身的动态代理
-
1、定义接口
public interface JavaProxyInterface { String getString(); }
-
2、实现这个接口的实现类
public class JavaProxyImpl implements JavaProxyInterface{ [@Override](https://my.oschina.net/u/1162528) public String getString() { return "this is result"; } }
-
3、代理类
package com.surfilter.mass; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.HashMap; public class JavaProxy { public static void main(String[] args) { //这里必须传入实现类,因为要newInstance() JavaProxyImpl proxy = (JavaProxyImpl) createLocalProxy(JavaProxyImpl.class); System.out.println(proxy.getString()); //实现不在本地,而是远端,所以这里传入接口,只要知道需要调用那个方法即可 JavaProxyInterface proxy1 = (JavaProxyInterface) createRPCProxy(JavaProxyInterface.class); System.out.println(proxy1.getString()); } /** * 创建本地代理对象 * 注意,这里传入的必须是实现类,实现类在本工程,不是RPC * 这样才能直接method.invoke(targetClass.newInstance(), args); * * 由于要newInstance(),上面又要获取接口,所以java动态代理的类必须实现接口 * 而CGlib和javasiset就不需要,直接传入业务类就行了,此类不需要实现接口 * * @param targetClass * @return */ public static Object createLocalProxy(Class targetClass) { Object o = Proxy.newProxyInstance( targetClass.getClassLoader(), //第一个参数,指定类加载器 targetClass.getInterfaces(), //第二个参数,这个类的接口是什么 new InvocationHandler() { //第三个参数,编写如何处理这个方法逻辑 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { return method.invoke(targetClass.newInstance(), args); } } ); return o; } /** * 创建RPC代理对象 * 注意,由于是RPC,接口实现不是在本地,而是在远端,所以这里面传入的是接口 * 主要是为了获取方法名字,参数,以及接口名字,从而组装json发送到远端 * 这样远端rpc服务器就能知道:1、调用那个类,2、那个方法,3、参数是什么 * * @param targetClass * @return */ public static Object createRPCProxy(Class targetClass) { //本身是接口 Object o = Proxy.newProxyInstance( targetClass.getClassLoader(), //第一个参数,指定类加载器 new Class[]{targetClass}, //第二个参数,这个类的接口是什么 new InvocationHandler() { //第三个参数,编写如何处理这个方法逻辑 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { HashMap<String, Object> requestMap = new HashMap<>(); requestMap.put("interfaceName", targetClass.getName()); requestMap.put("methodName", method.getName()); requestMap.put("args", args); // 通过netty发送这些参数到远端rpc服务器,这样就可以执行得到结果了 String result = "rpc result"; return result; } } ); return o; } }
2、CGLIB实现动态代理
-
1、maven依赖
<dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.2.4</version> </dependency>
-
2、接口
public interface CGLibProxyInterface { String getString(); }
-
3、业务类(可以实现接口,也可以不实现接口,不要求)
public class CGLibProxyImpl { public String getString() { return "this is result"; } }
-
4、代理类
import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.Method; /** * CGLibProxy 代理本地业务类,则需要传入业务实现类,但是这个类不要求实现接口(却别与JavaProxy) * 代理接口进行RPC远程过程调用,则需要传入接口 * * 不管传入的是接口还是实现类,都可以使用enhancer.setSuperclass(targetClass); * 因为他内部会做是否是接口的判断 * @Author liufu * @CreateTime 2018/3/28 9:00 */ public class CGLibProxy { public static void main(String[] args) { //创建本地的代理,需要传入真实的实现类,但是这个类不要求实现接口,这是和JavaProxy的区别 CGLibProxyImpl proxyLocal = (CGLibProxyImpl) createLocalProxy(CGLibProxyImpl.class); //创建rpc代理,需要传入接口,因为你也没有实现类,实现类在远端服务器 CGLibProxyInterface proxyRpc = (CGLibProxyInterface) createRemoteProxy(CGLibProxyInterface.class); System.out.println(proxyLocal.getString()); System.out.println(proxyRpc.getString()); } /** * 创建本地代理,需要传入实现类 * * @param targetClass * @return */ public static Object createLocalProxy(Class targetClass) { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(targetClass); enhancer.setCallback(new MethodInterceptor() { @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("before:" + method.getName()); //看清楚这里是要用methodProxy,而不是method Object invoke = methodProxy.invokeSuper(o, objects); System.out.println("after:" + method.getName()); return invoke; } }); return enhancer.create(); } /** * 创建rpc代理,只需要传入接口即可,因为只需要他的方法名,参数 * * @param targetClass * @return */ public static Object createRemoteProxy(Class targetClass) { Enhancer enhancer = new Enhancer(); /** *传入的是接口,也可以使用setSuperclass * 因为他内部会对class进行判断 * public void setSuperclass(Class superclass) { if(superclass != null && superclass.isInterface()) { this.setInterfaces(new Class[]{superclass}); } else if(superclass != null && superclass.equals(Object.class)) { this.superclass = null; } else { this.superclass = superclass; } } */ enhancer.setSuperclass(targetClass); //enhancer.setInterfaces(new Class[]{targetClass}); enhancer.setCallback(new MethodInterceptor() { @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("before:" + method.getName()); //传入的是接口,会报NoSuchMethodError异常 //Object result = methodProxy.invokeSuper(o, objects); System.out.println("after:" + method.getName()); return "this is rpc result"; } }); return enhancer.create(); } /** * 这个类是具体的业务处理类,上面在setCallback中使用的是匿名内部类 */ class ProxyCallBack implements MethodInterceptor { @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("before:" + method.getName()); //看清楚这里是要用methodProxy,而不是method Object invoke = methodProxy.invokeSuper(o, objects); System.out.println("after:" + method.getName()); return invoke; } } }
3、JavaSsist代理
-
1、maven依赖
<dependency> <groupId>org.javassist</groupId> <artifactId>javassist</artifactId> <version>3.21.0-GA</version> </dependency>
-
2、接口
public interface JavaSsistProxyInterface { String getString(); }
-
3、业务类
public class JavaSsistProxyImpl { public String getString(){ return "JavaSsistProxyImpl result"; } }
-
4、JavaSsist代理类
import javassist.util.proxy.MethodHandler; import javassist.util.proxy.ProxyFactory; import javassist.util.proxy.ProxyObject; import java.lang.reflect.Method; /** * JavaSsist代理测试 * @Author liufu * @CreateTime 2018/3/28 12:29 */ public class JavassistProxy { public static void main(String[] args) throws InstantiationException, IllegalAccessException { //java业务类代理 JavaSsistProxyImpl proxy = (JavaSsistProxyImpl) createLocalProxy(JavaSsistProxyImpl.class); System.out.println(proxy.getString()); //java接口代理 JavaSsistProxyInterface proxy1 = (JavaSsistProxyInterface) createRpcProxy(JavaSsistProxyInterface.class); System.out.println(proxy1.getString()); } /** * 创建本地的代理,可以使用具体业务类 * 而且这个类不要求实现接口,这是和JavaProxy的区别,和CGlibProxy很像 * 只是CGlibProxy的setSuperclass方法比较通用,可以传递interface也可以传递impl * @param targetClass * @return * @throws IllegalAccessException * @throws InstantiationException */ public static Object createLocalProxy(Class targetClass) throws IllegalAccessException, InstantiationException { ProxyFactory proxyFactory = new ProxyFactory(); proxyFactory.setSuperclass(targetClass); ProxyObject instance = (ProxyObject)proxyFactory.createClass().newInstance(); instance.setHandler(new MethodHandler() { @Override // method是真实的方法,method1是代理方法,都不为null // 一定要用method1.invoke,而不是method.invoke public Object invoke(Object o, Method method, Method method1, Object[] objects) throws Throwable { System.out.println(String.format("aop start, run method :%s", method.getName())); String result = "this is result" + method1.invoke(o, objects); System.out.println(String.format("aop end, finish run method :%s", method.getName())); return result; } }); return instance; } /** * 创建rpc代理,传入接口类,使用netty等客户端进行远程过程调用 * 注意:这个时候method1 == null * @param targetClass * @return * @throws IllegalAccessException * @throws InstantiationException */ public static Object createRpcProxy(Class targetClass) throws IllegalAccessException, InstantiationException { ProxyFactory proxyFactory = new ProxyFactory(); proxyFactory.setInterfaces(new Class[]{targetClass}); ProxyObject instance = (ProxyObject)proxyFactory.createClass().newInstance(); instance.setHandler(new MethodHandler() { @Override // method是真实的方法,此时一样不为null // method1是代理方法,此时为null public Object invoke(Object o, Method method, Method method1, Object[] objects) throws Throwable { System.out.println(String.format("aop start, run method :%s", method.getName())); String result = "this is result" + "===>RPC 返回了结果"; System.out.println(String.format("aop end, finish run method :%s", method.getName())); return result; } }); return instance; } }