标签:
package com.proxy; public interface Moveable { void move(); }Tank.java
package com.proxy; import java.util.Random; public class Tank implements Moveable{ @Override public void move() { //long start = System.currentTimeMillis(); //System.out.println("Tank Moving...");</span> try { Thread.sleep(new Random().nextInt(10000)); } catch (InterruptedException e) { e.printStackTrace(); } //long end = System.currentTimeMillis(); //System.out.println("time:"+(end-start));</span> } }需求:我们想要知道实现Moveable的实现类,move()方法的运行时间
package com.proxy; /** * 通过继承的方式来实现记录方法move()的运行时间 */ public class Tank2 extends Tank { public void move(){ long start = System.currentTimeMillis(); super.move(); long end = System.currentTimeMillis(); System.out.println("time:"+(end-start)); } }Client.java 测试类
package com.proxy; import com.proxy.Moveable; public class TankTimeProxy implements Moveable { Moveable t; public TankTimeProxy(Moveable t) { this.t = t; } public void move() { long start = System.currentTimeMillis(); System.out.println("startTime:" + start);</span> this.t.move(); long end = System.currentTimeMillis(); System.out.println("time:" + (end - start));</span> } }
package com.proxy; public class TankLogProxy implements Moveable{ Moveable t; public TankLogProxy(Moveable t){ super(); this.t = t; } @Override public void move() { System.out.println("Tank Start ....");</span> t.move(); System.out.println("Tank Stop ....");</span> }TankTimeProxy.java
package com.proxy; public class TankTimeProxy implements Moveable { Moveable t; public TankTimeProxy(Moveable t){ super(); this.t = t; } @Override public void move() { long start = System.currentTimeMillis(); System.out.println("startTime:"+start);</span> t.move(); long end = System.currentTimeMillis(); System.out.println("time:"+(end-start));</span> } }测试类Client.java
package com.proxy; public class Client { public static void main (String [] args){ //先记录日志,再记录时间 Tank t = new Tank(); TankTimeProxy ttp = new TankTimeProxy(t); TankLogProxy tlp = new TankLogProxy(ttp); Moveable m = tlp; m.move(); /**先记录时间,再记录日志*/ /** Tank t = new Tank(); TankLogProxy tlp = new TankLogProxy(t); TankTimeProxy ttp = new TankTimeProxy(tlp); Moveable m = ttp; m.move(); */ } }运行结果:
Tank Start .... startTime:1465278163874 Tank Moving... time:4330 Tank Stop ....以上就是静态代理的典型例子。但是问题来了,我们能不能动态生成一个代理,能够做为任何目标的代理(前提是代理的类和被代理的类都实现了共同的接口)。
package com.proxy.test; import com.proxy.Moveable; import com.proxy.Tank; import javax.tools.JavaCompiler; import javax.tools.StandardJavaFileManager; import javax.tools.ToolProvider; import java.io.File; import java.io.FileWriter; import java.lang.reflect.Constructor; import java.net.URL; import java.net.URLClassLoader; public class Test1 { public static void main(String[] args) throws Exception { String rt = "\r\n"; String src = "package com.proxy;" + rt + " public class TankTimeProxy implements Moveable {" + rt + " Moveable t;" + rt + " public TankTimeProxy(Moveable t){" + rt + " super();" + rt + " this.t = t;" + rt + " }" + rt + " @Override" + rt + " public void move() {" + rt + " long start = System.currentTimeMillis();" + rt + " System.out.println(\"startTime:\"+start);" + rt + " t.move();" + rt + " long end = System.currentTimeMillis();" + rt + " System.out.println(\"time:\"+(end-start));" + rt + " }" + rt + " }"; //我们想让这段代码编译,如何做呢? //1.首先,我们可以把这段代码写到临时文件中 String fileName = System.getProperty("user.dir") + "/src/com/proxy/TankTimeProxy.java"; File f = new File(fileName); FileWriter fw = new FileWriter(f); fw.write(src); fw.flush(); fw.close(); //2.编译生成的Java文件生成class文件 //获取此平台提供的 Java? 编程语言编译器 JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); StandardJavaFileManager fileMagr = compiler.getStandardFileManager(null, null, null); Iterable units = fileMagr.getJavaFileObjects(fileName); JavaCompiler.CompilationTask t = compiler.getTask(null, fileMagr, null, null, null, units); t.call(); fileMagr.close(); //3.将编译生成的class的load 到内存,生成新对象 //注意:使用ClassLoader()必须保证那个class在classPath路径下, //所以我们使用URLClassLoader URL[] urls = new URL[]{new URL("file:/" + System.getProperty("user.dir") + "/src")}; URLClassLoader ul = new URLClassLoader(urls); Class c = ul.loadClass("com.proxy.TankTimeProxy"); System.out.println(c); //4.生成代理类对象 Constructor ctr = c.getConstructor(Moveable.class); Moveable m = (Moveable)ctr.newInstance(new Tank()); m.move(); } }运行结果:
class com.proxy.TankTimeProxy startTime:1465283901100 Tank Moving... time:1043问题1:现在我们可以实现指定接口(Moveable)的动态代理,但是我们要产生实现任何接口的代理,应该怎么做?
package com.proxy; import java.lang.reflect.Method; //为方法处理逻辑定义一个统一的接口 public interface InvocationHandler { public void invoke(Object o, Method m); }2.通过调用Proxy.newProxyInstance(Class infce, InvocationHandler h)来产生代理类的代理对象。
package com.proxy; import javax.tools.JavaCompiler; import javax.tools.StandardJavaFileManager; import javax.tools.ToolProvider; import java.io.File; import java.io.FileWriter; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.net.URL; import java.net.URLClassLoader; public class Proxy { public static Object newProxyInstance(Class infce, InvocationHandler h) throws Exception { String rt = "\r\n"; String methodStr = ""; Method[] methods = infce.getMethods(); /**写一个循环,将所用的方法都拿出来*/ for(Method m : methods) { methodStr += "@Override" + rt + "public void " + m.getName() + "() {" + rt + " try {" + rt + " Method md = " + infce.getName() + ".class.getMethod(\"" + m.getName() + "\");" + rt + " h.invoke(this, md);" + rt + " }catch(Exception e) {e.printStackTrace();}" + rt + "}"; } String src = "package com.proxy;" + rt + "import java.lang.reflect.Method;" + rt + " public class $Proxy1 implements "+infce.getName()+" {" + rt + " com.proxy.InvocationHandler h;" + rt + " public $Proxy1(InvocationHandler h){" + rt + " this.h = h;" + rt + " }" + rt + methodStr + " }"; //1.首先,我们可以把这段代码写到临时文件中 String fileName = System.getProperty("user.dir") + "/src/com/proxy/$Proxy1.java"; File f = new File(fileName); FileWriter fw = new FileWriter(f); fw.write(src); fw.flush(); fw.close(); //2.编译生成的Java文件生成class文件 JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); StandardJavaFileManager fileMagr = compiler.getStandardFileManager(null, null, null); Iterable units = fileMagr.getJavaFileObjects(fileName); JavaCompiler.CompilationTask t = compiler.getTask(null, fileMagr, null, null, null, units); t.call(); fileMagr.close(); //3.将编译生成的class的load 到内存,生成新对象 URL[] urls = new URL[]{new URL("file:/" + System.getProperty("user.dir") + "/src")}; URLClassLoader ul = new URLClassLoader(urls); Class c = ul.loadClass("com.proxy.$Proxy1"); System.out.println(c); //4.生成代理类对象 Constructor ctr = c.getConstructor(InvocationHandler.class); Object m = ctr.newInstance(h); return m; } }3.现在我们可以通过新建一个Tank类(被代理类),InvocationHandler的实现类TimeHandler(业务逻辑的处理) 来对代理模式进行进一步的说明。
package com.proxy; import java.util.Random; public class Tank implements Moveable{ @Override public void move() { System.out.println("Tank Moving..."); try { Thread.sleep(new Random().nextInt(10000)); } catch (InterruptedException e) { e.printStackTrace(); } } }b.TimeHandler类,实现的InvationHandler类,加上自己的代理逻辑,要加上被代理对象要调用的方法。
package com.proxy; import java.lang.reflect.Method; public class TimeHandler implements InvocationHandler { private Object target; //定义被代理对象的一个引用 public TimeHandler(Object target){ super(); this.target = target; } @Override public void invoke(Object o, Method m) { long start = System.currentTimeMillis(); System.out.println("startTime :"+start);</span> try { m.invoke(target);//调用被代理对象的m方法 } catch (Exception e) { e.printStackTrace(); } long end = System.currentTimeMillis(); System.out.println("endTime :"+end); System.out.println("useTime:" + (end-start));</span> } }c.Client.java测试类
package com.proxy; public class Client { public static void main (String [] args) throws Exception { Tank t = new Tank(); //定义一个被代理的对象 InvocationHandler h = new TimeHandler(t); //调用Proxy.newProxyInstance()方法生成一个代理对象。 Moveable m = (Moveable) Proxy.newProxyInstance(Moveable.class, h); m.move(); } }现在我们来梳理一下上面例子的逻辑
package com.proxy.test2; public interface UserMgr { void addUser(); }UserMgrImpl.java 被代理的类
package com.proxy.test2; public class UserMgrImpl implements UserMgr { @Override public void addUser() { System.out.println("1: 插入记录到user表"); System.out.println("2: 在另外一张表写日志"); } }TransactionHandler.java ,InvocationHandler具体的实现类
package com.proxy.test2; import com.proxy.InvocationHandler; import java.lang.reflect.Method; public class TransactionHandler implements InvocationHandler { private Object target; public TransactionHandler(Object target) { this.target = target; } @Override public void invoke(Object o, Method m) { System.out.println("Transaction Start"); try { m.invoke(target); } catch (Exception e) { e.printStackTrace(); } System.out.println("Transaction Commit"); } }Client.java
package com.proxy.test2; import com.proxy.InvocationHandler; import com.proxy.Proxy; public class Client { public static void main(String[] args) throws Exception { UserMgr mgr = new UserMgrImpl(); InvocationHandler h = new TransactionHandler(mgr); //TimeHandler h2 = new TimeHandler(h); UserMgr u = (UserMgr) Proxy.newProxyInstance(UserMgr.class, h); u.addUser(); } }5.JDK动态代理的实现
InvocationHandler
是代理实例的调用处理程序 实现的接口public interface PersonDao { public void savePerson(); }PersonDaoImpl.java
public class PersonDaoImpl implements PersonDao{ public void savePerson() { System.out.println("save person"); } }
public class Transaction { public void beginTransaction(){ System.out.println("begin transaction"); } public void commit(){ System.out.println("commit"); } }
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; /** * 1、引入personDao和Transaction * 2、完成invoke方法 */ public class MyInterceptor implements InvocationHandler{ private Object target; private Transaction transaction; public MyInterceptor(Object target,Transaction transaction){ this.target = target; this.transaction = transaction; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //在invoke()中做事务判断。 if(method.getName().equals("savePerson")||method.getName().equals("updatePerson")){ this.transaction.beginTransaction(); method.invoke(this.target, args);//调用目标类的目标方法 this.transaction.commit(); }else{ method.invoke(this.target, args);//调用目标类的目标方法 } return null; } }
import java.lang.reflect.Proxy; import org.junit.Test; /** * 问题: * 1、拦截器中的invoke方法在什么时候被调用的? * 在代理对象调用方法的时候,进入了拦截器中的invoke方法 * 2、拦截器中的method参数是什么?在什么时候由实参传递给形参的? * 代理对象的方法的名称是什么,method参数就是什么 * 代理对象调用方法的时候,进入了拦截器中的invoke方法,这个时候,传递参数 * 3、生成的代理对象实现了接口,代理对象的方法体的内容是什么? * 方法体的内容就是拦截器中的invoke方法体的内容 * * jdkproxy的优点: 动态的产生代理对象,所以只需要用一个拦截器就可以了 * jdkproxy的缺点: 如果在invoke方法中做事务的判断,将是一件很复杂的事情 * 比如我们在Service接口中有20个类 ,20个方法。30个方法不需要事务,370 个方法需要事务。 * 在invoke中做事务判断很麻烦。程序员还是写拦截器了,写拦截器中的invoke方法了,所以invoke方法还需要修改 。 * 所以这个解决方式还是不靠谱。 * * 说明: 目标类和代理类实现了共同的接口 */ public class ProxyTest { @Test public void testProxy(){ PersonDao target = new PersonDaoImpl(); Transaction transaction = new Transaction(); MyInterceptor interceptor = new MyInterceptor(target, transaction); /** * 第一个参数: 目标类的类加载器 * 第二个参数: 目标类实现的所有的接口 * 第三个参数: 拦截器 */ PersonDao personDao = (PersonDao)Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(), interceptor); personDao.savePerson(); } }运行结果:
begin transaction save person commit案例2:
public interface SalaryManager { public void showSalary(); }SalaryManagerImpl.java
public class SalaryManagerImpl implements SalaryManager{ public void showSalary() { System.out.println("正在查看工资"); } }
public class Logger { public void logging(){ System.out.println("logging"); } }Security.java
public class Security { public void security(){ System.out.println("security"); } }Privilege.java
public class Privilege { private String access; public String getAccess() { return access; } public void setAccess(String access) { this.access = access; } }MyInterceptor.java
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class MyInterceptor implements InvocationHandler{ private Object target; private Logger logger; private Security security; private Privilege privilege; public MyInterceptor(Object target,Logger logger, Security security, Privilege privilege) { super(); this.target = target; this.logger = logger; this.security = security; this.privilege = privilege; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //启动日志 this.logger.logging(); //安全性的框架 this.security.security(); //判断权限 if(this.privilege.getAccess().equals("admin")){ method.invoke(this.target, args);//调用目标方法 }else{ System.out.println("没有权限执行"); } return null; } }SalaryTest.java
import java.lang.reflect.Proxy; import org.junit.Test; public class SalaryTest { @Test public void testSalary(){ Logger logger = new Logger(); Security security = new Security(); Privilege privilege = new Privilege();<pre name="code" class="java">public interface PersonDao { public void savePerson(); }
target.getClass().getInterfaces(),interceptor);<span style="font-family: Arial, Helvetica, sans-serif;"> </span>salaryManager.showSalary();}}
public interface PersonDao { public void savePerson(); }PersonDaoImpl.java
public class PersonDaoImpl implements PersonDao{ public void savePerson() { System.out.println("save person"); } }Transaction.java
public class Transaction { public void beginTransaction(){ System.out.println("begin transaction"); } public void commit(){ System.out.println("commit"); } }MyInterceptor.java
import java.lang.reflect.Method; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; /** * 1、引入personDao和Transaction * 2、完成invoke方法 */ public class MyInterceptor implements MethodInterceptor{ private Object target; private Transaction transaction; public MyInterceptor(Object target,Transaction transaction){ this.target = target; this.transaction = transaction; } //产生代理对象(这是一个代码增强机制,它是在JVM内部去实现的) public Object createProxy(){ Enhancer enhancer = new Enhancer(); enhancer.setCallback(this);//this代表拦截器对象 enhancer.setSuperclass(target.getClass());//设置代理类的父类为目标类 return enhancer.create(); } /** * 该方法的内容和jdkpoxy中的invoke方法的内容是一样的 */ public Object intercept(Object arg0, Method method, Object[] args,MethodProxy arg3) throws Throwable { this.transaction.beginTransaction(); method.invoke(this.target, args); this.transaction.commit(); return null; } }ProxyTest.java
import org.junit.Test; /** * JDK代理和cglib代理的主要区别: * Jdk代理的方式:目标类和代理类实现了共同的接口 * Cglib动态代理的方式:目标类是代理类的父类 */ public class ProxyTest { @Test public void testProxy(){ PersonDaoImpl target = new PersonDaoImpl(); Transaction transaction = new Transaction(); MyInterceptor interceptor = new MyInterceptor(target, transaction); PersonDaoImpl proxy = (PersonDaoImpl)interceptor.createProxy(); proxy.savePerson(); } }运行结果:
begin transaction save person commit
标签:
原文地址:http://blog.csdn.net/zhuwenchao90/article/details/51596937