动态代理讲解
什么是动态代理?
一种用于转发请求,进行特殊处理的机制,“动态”应该指的是“运行期”。
.为什么使用动态代理?
可以对请求进行任何处理(如事务,日志等)
.哪些地方需要动态代理?
不允许直接访问某些类;对访问要做特殊处理等
JVM可以在运行时期动态生成出类的字节码,这种动态生成的类往往被用作代理类,即动态代理类
JVM生成的动态类必须实现一个或多个接口,所以JVM生成的动态类只能用作具有具有相同接口的目标类的代理
CGLIB库可以动态生成一个类的子类,该子类可以用作该类的代理,如果,没有实现接口的类生成动态代理类可以使用CGLIB库
代理类的各个方法中通常除了调用目标的相应方法和对外返回目标返回的结果外,还可以再代理方法中如下四个位置增加
系统功能代码:
1、在调用目标方法之前;
2、在调用目标方法之后;
3、在调用目标方法前后;
4、在处理目标方法异常的catch块中;
创建动态类:
创建一个借口
<span style="font-size:18px;"><strong>import java.lang.reflect.Method;
public interface Advice {
public void beforeMethod(Method method);
public void afterMethod(Method method);
}
</strong></span>
<span style="font-size:18px;"><strong>import java.lang.reflect.Method;
public interface Advice {
public void beforeMethod(Method method);
public void afterMethod(Method method);
}
</strong></span>
<span style="font-size:18px;"><strong>创建一个实现接口的类 import java.lang.reflect.Method; public class MyAdvice implements Advice{ long beginTime = 0; public void afterMethod(Method method) { System.out.println("学习结束了"); long endTime = System.currentTimeMillis(); System.out.println(method.getName() + " 运行时间" + (endTime - beginTime)); } public void beforeMethod(Method method) { System.out.println("开始学习了"); beginTime = System.currentTimeMillis(); }
<span style="font-size:18px;"><strong>import java.lang.reflect.Constructor; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.ArrayList; import java.util.Collection; public class ProxyText { public static void main(String[] args) throws Exception, NoSuchMethodException { // 获取字节码 Class clazzProxy1 = Proxy.getProxyClass(Collection.class .getClassLoader(), Collection.class); System.out.println(clazzProxy1.getName()); System.out.println("----------begin constructors list------------"); /* * $Proxy0() $Proxy0(InvocationHandier,int) */ // 获取所有构造方法 Constructor[] constructors = clazzProxy1.getConstructors(); for (Constructor constructor : constructors) { String name = constructor.getName(); StringBuilder sBuilder = new StringBuilder(name); sBuilder.append("("); Class[] clazzPrams = constructor.getParameterTypes(); for (Class clazzPram : clazzPrams) { if (clazzPrams != null && clazzPrams.length != 0) { sBuilder.append(clazzPram.getName()).append(","); } } sBuilder.append(")"); System.out.println(sBuilder.toString()); System.out.println("-----------begin methods llist------------"); // 获得所有的方法 Method[] methods = clazzProxy1.getMethods(); for (Method method : methods) {// 遍历数组 String name1 = method.getName();// 获取方法名 StringBuilder sBuilder1 = new StringBuilder(name1);// 添加容器 sBuilder1.append("("); Class[] clazzPrams1 = method.getParameterTypes();// 返回描述了此 // Method // 对象所表示的方法的形参类型 for (Class clazzPram1 : clazzPrams1) { sBuilder1.append(clazzPram1.getName()); } sBuilder1.append(")"); System.out.println(sBuilder1.toString()); } System.out .println("-----------begin create instance object-----------"); // 创建InvocationHandler的实例对象 Constructor constructor1 = clazzProxy1 .getConstructor(InvocationHandler.class); // 第一种方法 创建MyInvocationHandler1并实现InvocationHandler接口 class MyInvocationHandler1 implements InvocationHandler { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { return null; } } Collection proxy1 = (Collection) constructor1 .newInstance(new MyInvocationHandler1()); // 第二种创建方法:用匿名内部类 Collection proxy2 = (Collection) constructor1 .newInstance(new InvocationHandler() { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { return null; } }); final ArrayList al = new ArrayList(); Collection proxy3 = (Collection) getProxy(al,new MyAdvice()); // proxy3.add("abc"); // proxy3.add("bcd"); // proxy3.add("cde"); System.out.println(proxy3.size()); } } // //第三种创建的方法:使用newProxyInstance方法 (抽取方法) private static Object getProxy(final Object target, final Advice advice) { Object proxy3 = Proxy.newProxyInstance( target.getClass().getClassLoader(), // new Class[]{Collection.class}, target.getClass().getInterfaces(), new InvocationHandler() { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { /* * long beginTime = System.currentTimeMillis(); Object * retVal = method.invoke(target, args); long endTime = * System.currentTimeMillis(); * * System.out.println(method.getName() + " 运行时间" + * (endTime - beginTime)); return retVal; */ advice.beforeMethod(method); Object retVal = method.invoke(target, args); advice.afterMethod(method); return retVal; } }); return proxy3; } } </strong></span>