标签:ssl http 服务 com pre error 引入 rri 动态
一、概述
public interface Service { public void add(); }
被代理类作为接口的一种实现,定义如下:
public class ServiceImpl implements Service { @Override public void add() { System.out.println("添加用户!"); } }
假如我们要求被代理类加一些日志操作,代理类就可以做如下定义:
public class ServiceProxy implements Service { private Service service; public ServiceProxy(Service service) { this.service = service; } @Override public void add() { System.out.println("服务开始"); service.add(); System.out.println("服务结束"); } }
编写测试类:
public class TestMain { public static void main(String[] args) { //创建被代理对象 Service service = new ServiceImpl(); //使用被代理对象来创建代理对象 Service proxy = new ServiceProxy(service); //执行方法 proxy.add(); } }
运行测试程序,打印结果如下:
从上面的代理可以看到,静态代理类只能为特定的接口服务,如果要服务多类型的对象,就要为每一种对象进行代理。我们就会想是否可以通过一个代理类完成全部的代理功能,于是引入了动态代理的功能。
三、动态代理
//该方法用于获取指定代理对象所关联的调用处理器 static InvocationHandler getInvocationHandler(Object proxy); //该方法用于获取关联于指定类装载器和一组接口的动态代理类的类对象 static Class getProxyClass(ClassLoader loader, Class[] interfaces); //该方法用于判断指定类对象是否是一个动态代理类 static boolean isProxyClass(Class cl); //该方法用于为指定类装载器、一组接口及调用处理器生成动态代理类实例 static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h);
InvocationHandler: 它是调用处理器接口,自定义一个invoke方法,用于集中处理在动态代理类对象上的方法调用,通常在该方法中实现对被代理类的代理访问
//该方法负责集中处理动态代理类上所有方法调用 //第一个参数是代理类实例 //第二个参数是被调用的方法对象 //第三个参数是方法的调用参数 //调用处理器根据这三个参数进行预处理或者分派到被代理类实例上反射执行 Object invoke(Object proxy, Method method, Object[] args);
实现Java的动态代理,具体有以下四个步骤:
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class ServiceHandler implements InvocationHandler { private Object o; public ServiceHandler(Object o) { this.o = o; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("服务开始"); //invoke表示对带有指定参数的指定对象调用由此Method对象表示的底层方法 Object result = method.invoke(o, args); System.out.println("服务结束"); return result; } }
编写测试类:
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; public class TestMain { public static void main(String[] args) { // 创建被代理对象 Service service = new ServiceImpl(); InvocationHandler handler = new ServiceHandler(service); Service s = (Service) Proxy.newProxyInstance(service.getClass().getClassLoader(), service.getClass().getInterfaces(), handler); s.add(); } }
运行测试程序,打印结果跟静态代理打印的结果是一样的。
//通过Proxy为包括Interface接口在内的一组接口动态创建代理类的Class对象 Class clazz = Proxy.getProxyClass(classLoader, new Class[]{Interface.class, ...}); //通过反射从生成的Class对象中获取构造函数对象 Constructor constructor = clazz.getConstructor(new Class[]{InvocationHandler.class}); //通过构造函数对象创建动态代理类的实例 Interface proxy = constructor.newInstance(new Object[]{handler});
newProxyInstance函数的内部实现为:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException { //检查h不为空,否则抛异常 Objects.requireNonNull(h); //获得与指定类装载器和一组接口相关的代理类的Class对象 final Class<?>[] intfs = interfaces.clone(); //检查接口的Class对象是否对类装载器可见,并且与类装载器所能识别的接口的Class对象是完全相同的 final SecurityManager sm = System.getSecurityManager(); if (sm != null) { checkProxyAccess(Reflection.getCallerClass(), loader, intfs); } //获得与指定类装载器和一组接口相关的代理类的Class对象 Class<?> cl = getProxyClass0(loader, intfs); try { if (sm != null) { checkNewProxyPermission(Reflection.getCallerClass(), cl); } //通过反射获取构造函数对象并生成代理类实例 final Constructor<?> cons = cl.getConstructor(constructorParams); final InvocationHandler ih = h; if (!Modifier.isPublic(cl.getModifiers())) { AccessController.doPrivileged(new PrivilegedAction<Void>() { public Void run() { cons.setAccessible(true); return null; } }); } return cons.newInstance(new Object[]{h}); } catch (IllegalAccessException|InstantiationException e) { throw new InternalError(e.toString(), e); } catch (InvocationTargetException e) { Throwable t = e.getCause(); if (t instanceof RuntimeException) { throw (RuntimeException) t; } else { throw new InternalError(t.toString(), t); } } catch (NoSuchMethodException e) { throw new InternalError(e.toString(), e); } }
五、总结
标签:ssl http 服务 com pre error 引入 rri 动态
原文地址:https://www.cnblogs.com/africancu/p/10383581.html