《Java与模式》一书中这样介绍代理模式的:
JDK动态代理的核心:
Proxy – 用于创建给定接口的子类,在内存中动态的创建。$Proxy0. - 此类只使用一次。
InovocationHandler– 执行句柄。在执行时可以获取被代理类的所有反射。 - 用户的每一次调用都会被这个句柄拦截到。
JDK动态代理的作用:
在内存中创建某个接口的子类。
拦截所有在代理上执行的方法。( 除了getClass方法。)
代码结构如下:
package Interview;
public interface IInteviewer {
//面试者面试
String Interview(String name);
}
package Interview;
public class Inteviewer implements IInteviewer{
@Override
public String Interview(String name) {
System.out.println("您好,我是今天的面试者 "+ name);
return name;
}
}
package Interview;
import java.lang.reflect.Proxy;
public class ProxyDemo {
public static void main(String[] args) {
final IInteviewer obj = new Inteviewer();
Object proxyedObj =
Proxy.newProxyInstance(
ProxyDemo.class.getClassLoader(), //类加载器
new Class[]{IInteviewer.class}, //被代理类的接口数组
new InterviewProxy(obj));
IInteviewer obj2 = (IInteviewer) proxyedObj;
obj2.Interview("阿呆");
}
}
package Interview;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class InterviewProxy implements InvocationHandler {
private Object obj ;
public InterviewProxy(Object obj) {
this.obj = obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object invoke = method.invoke(obj, args);
return invoke;
}
}
运行结果如下:
当然这个只是简单的得到了代理对象,并调用代理对象的方法。貌似代理对象没有起到多大的作用,下面我们就用代理模拟spring的事务(简单演示)。
package com.demo.se.proxy;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(value=ElementType.METHOD)
public @interface Tx {
}
package com.demo.se.proxy;
public interface IOne {
@Tx
void save();//添加需要处理事务的注解
Object query(String id);
}
package com.demo.se.proxy;
public class One implements IOne {
public void save() {
System.err.println("保存。。。");
}
public Object query(String id) {
System.err.println("根据ID查询。。。。id=" + id);
return id;
}
}
package com.demo.se.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class TxProxy implements InvocationHandler {
private Object obj;
public TxProxy(Object obj) {
super();
this.obj = obj;
}
//接收一个被代理的对象
public static Object newProxy(Object o){
Object proxy = Proxy.newProxyInstance(
TxProxy.class.getClassLoader(),
o.getClass().getInterfaces(),
new TxProxy(o));
return proxy;
}
//使用泛型,接收被代理的Class对象
public static T newProxy(Class cls){
Object o = null;
try {
o = cls.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
Object proxy = Proxy.newProxyInstance(TxProxy.class.getClassLoader(),
o.getClass().getInterfaces(),
new TxProxy(o));
return (T)proxy;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object res = null;
if(method.isAnnotationPresent(Tx.class)){//判断是否添加了Tx事务注解
try{
System.err.println("开始拦截..从当前线程局部对象中获取一个连接");
res = method.invoke(this.obj, args);
System.err.println("拦截完成提交");
}catch(Exception e){
System.err.println("回滚");
throw new RuntimeException(e.getMessage(),e);
}finally{
System.err.println("结束。。。放回连接池");
}
}else{
res = method.invoke(this.obj, args);
}
return res;
}
}
package com.demo.se.proxy;
import org.junit.Test;
public class TxTest {
@Test
public void t1(){
IOne one = TxProxy.newProxy(One.class);
one.save(); //此方法将会处理事务
one.query("001");
}
}
通过以上代码相信你对代理应该有了一个认识,下篇介绍cglib代理以及简单的mybatis中使用代理的。