标签:
package com.proxy;
public interface Moveable {
void move();
}Tank.javapackage 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.javapackage 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.javapackage 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.javapackage 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.javapublic 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.javapublic class SalaryManagerImpl implements SalaryManager{
public void showSalary() {
System.out.println("正在查看工资");
}
}public class Logger {
public void logging(){
System.out.println("logging");
}
}Security.javapublic class Security {
public void security(){
System.out.println("security");
}
}Privilege.javapublic class Privilege {
private String access;
public String getAccess() {
return access;
}
public void setAccess(String access) {
this.access = access;
}
}MyInterceptor.javaimport 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.javaimport 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.javapublic class PersonDaoImpl implements PersonDao{
public void savePerson() {
System.out.println("save person");
}
}Transaction.javapublic class Transaction {
public void beginTransaction(){
System.out.println("begin transaction");
}
public void commit(){
System.out.println("commit");
}
}MyInterceptor.javaimport 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.javaimport 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