例程1 HelloService.java
package proxy;
import java.util.Date;
public interface HelloService{
public String echo(String msg);
public Date getTime();
}
例程2 HelloServiceImpl.java
package proxy;
import java.util.Date;
public class HelloServiceImpl implements HelloService{
public String echo(String msg){
return "echo:"+msg;
}
public Date getTime(){
return new Date();
}
}
例程3 HelloServiceProxy.java
package proxy;
import java.util.Date;
public class HelloServiceProxy implements HelloService{
//表示被代理的HelloService 实例
private HelloService helloService;
public HelloServiceProxy(HelloService helloService){
this.helloService=helloService;
}
public void setHelloServiceProxy(HelloService helloService){
this.helloService=helloService;
}
public String echo(String msg){
//预处理
System.out.println("before calling echo()");
//调用被代理的HelloService 实例的echo()方法
String result=helloService.echo(msg);
//事后处理
System.out.println("after calling echo()");
return result;
}
public Date getTime(){
//预处理
System.out.println("before calling getTime()");
//调用被代理的HelloService 实例的getTime()方法
Date date=helloService.getTime();
//事后处理
System.out.println("after calling getTime()");
return date;
}
}
例程4 Client1.java
package proxy;
public class Client1{
public static void main(String args[]){
HelloService helloService=new HelloServiceImpl();
HelloService helloServiceProxy=new HelloServiceProxy(helloService);
System.out.println(helloServiceProxy.echo("hello"));
}
}
运行Client1 类,打印结果如下:
before calling echo()
after calling echo()
echo:hello
例程3 的HelloServiceProxy类的源代码是由程序员编写的,在程序运行前,它的.class文件就已经存在了,这种代理类称为静态代理类。
java 使用动态代理 和ThreadLocal实现事务管理实例
概念
远程代理控制访问远程对象虚拟代理控制访问创建开销大的资源保护代理基于权限控制对资源的访问
代理模式分类
动态代理
一个关于静态代理的例子
package ProxyMode;
/*
* 抽象接口,对应类图中的Subject
*
*/
public interface Subject {
public void SujectShow();
}
package ProxyMode;
public class RealSubject implements Subject{
@Override
public void SujectShow() {
// TODO Auto-generated method stub
System.out.println("杀人是我指使的,我是幕后黑手!By---"+getClass());
}
}
然后定义一个代理类,黑帮,拿钱办事,但不是幕后黑手
package ProxyMode;
import proxy.RealeSubject;
public class ProxySubject implements Subject{
private Subject realSubject;//代理类中有 老板的引用。
public Subject TakeCall() //通过电话联系
{
return new RealSubject();
}
public void Before()
{
System.out.println("我只是一个代理类,在做事情之前我先声明,接下来的事情跟我无关,我只是受人指使!By---"+getClass());
}
public void After()
{
System.out.println("正如事情还没有发生之前讲的一样,我只是个路人,上面做的事情跟我无关,我是受人指使的! By---"+getClass());
}
@Override
public void SujectShow() {
// TODO Auto-generated method stub
Object o=TakeCall(); //代理类接到了一个电话
if(checked(o)) //检查这个电话是不是老板打过来的
{
Before();
this.realSubject=(Subject)o;
realSubject.SujectShow();
After();
}
else {
System.out.println("不好意思,你权限不够,我帮不了你!");
}
}
boolean checked(Object o) //权限检查,这年头不是谁都可以冒充老板的
{
if(o instanceof RealSubject )
return true;
return false;
}
}
package ProxyMode;
public class ProxyTest {
public static void main(String[] args)
{
ProxySubject proxy=new ProxySubject();
proxy.SujectShow();
}
}
执行结果:
我只是一个代理类,在做事情之前我先声明,接下来的事情跟我无关,我只是受人指使!By---class ProxyMode.ProxySubject
杀人是我指使的,我是幕后黑手!By---class ProxyMode.RealSubject
正如事情还没有发生之前讲的一样,我只是个路人,上面做的事情跟我无关,我是受人指使的! By---class ProxyMode.ProxySubject
动态代理概念及类图
动态代理实现过程
一个具体的例子
package ProxyMode;
/*
* 抽象接口,对应类图中的Subject
*
*/
public interface Subject {
public void SujectShow();
}
package ProxyMode;
public class RealSubject implements Subject{
@Override
public void SujectShow() {
// TODO Auto-generated method stub
System.out.println("杀人是我指使的,我是幕后黑手!By---"+getClass());
}
}
package ProxyMode;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class ProxyHandler implements InvocationHandler {
private Object proxied;
public ProxyHandler( Object proxied )
{
this.proxied = proxied;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("准备工作之前:");
//转调具体目标对象的方法
Object object= method.invoke( proxied, args);
System.out.println("工作已经做完了!");
return object;
}
}
package ProxyMode;
import java.lang.reflect.Proxy;
public class DynamicProxy {
public static void main( String args[] )
{
RealSubject real = new RealSubject();
Subject proxySubject = (Subject)Proxy.newProxyInstance(Subject.class.getClassLoader(),
new Class[]{Subject.class},
new ProxyHandler(real));
proxySubject.SujectShow();;
}
}
测试结果
准备工作之前:
杀人是我指使的,我是幕后黑手!By---class ProxyMode.RealSubject
工作已经做完了!
Proxy和InvocationHandler重要部分源码分析
清单 1. Proxy 的静态方法
// 方法 1: 该方法用于获取指定代理对象所关联的调用处理器,比如上面代码中的ProxyHandler
static InvocationHandler getInvocationHandler(Object proxy)
// 方法 2:该方法用于获取关联于指定类装载器和一组接口的动态代理类的类对象
static Class getProxyClass(ClassLoader loader, Class[] interfaces)
// 方法 3:该方法用于判断指定类对象是否是一个动态代理类
static boolean isProxyClass(Class cl)
// 方法 4:该方法用于为指定类装载器、一组接口及调用处理器生成动态代理类实例
static Object newProxyInstance(ClassLoader loader, Class[] interfaces,
InvocationHandler h)
下面重点看看newProxyInstance方法:
public static Object newProxyInstance(ClassLoader loader,
Class>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException {
// 检查 h 不为 空,否则抛异常
if (h == null) {
throw new NullPointerException();
}
// 获得与制定类装载器和一组接口相关的代理类类型对象
Class cl = getProxyClass(loader, interfaces);
// 通过反射获取构造函数对象并生成代理类实例
try {
Constructor cons = cl.getConstructor(constructorParams);
return (Object) cons.newInstance(new Object[] { h });
} catch (NoSuchMethodException e) { throw new InternalError(e.toString());
} catch (IllegalAccessException e) { throw new InternalError(e.toString());
} catch (InstantiationException e) { throw new InternalError(e.toString());
} catch (InvocationTargetException e) { throw new InternalError(e.toString());
}
}
看这个方法的三个参数
for (int i = 0; i < interfaces.length; i++) {
// 验证类加载程 序 解 析 该接口到同一类对象的名称。
String interfaceName = interfaces[i].getName();
Class> interfaceClass = null;
try {
interfaceClass = Class.forName(interfaceName, false, loader);
} catch (ClassNotFoundException e) {
}
if (interfaceClass != interfaces[i]) {
throw new IllegalArgumentException(
interfaces[i] + " is not visible from class loader");
}
// 验证类对象真正代表一个接口
if (!interfaceClass.isInterface()) {
throw new IllegalArgumentException(
interfaceClass.getName() + " is not an interface");
}
//验证这个接口是不是重复的
if (interfaceSet.contains(interfaceClass)) {
throw new IllegalArgumentException(
"repeated interface: " + interfaceClass.getName());
}
interfaceSet.add(interfaceClass); //interfaceset是一个hashset集合
interfaceNames[i] = interfaceName;
}
从 loaderToCache 映射表中获取以类装载器对象为关键字所对应的缓存表,如果不存在就创建一个新的缓存表并更新到 loaderToCache。
synchronized (cache) {
do {
// 以接口名字列表作为关键字获得对应 cache 值
Object value = cache.get(key);
if (value instanceof Reference) {
proxyClass = (Class) ((Reference) value).get();
}
if (proxyClass != null) {
// 如果已经创建,直接返回,这里非常重要,如果已经创建过代理类,那么不再创建
return proxyClass;
} else if (value == pendingGenerationMarker) {
// 代理类正在被创建,保持等待
try {
cache.wait();
} catch (InterruptedException e) {
}
// 等待被唤醒,继续循环并通过二次检查以确保创建完成,否则重新等待
continue;
} else {
// 标记代理类正在被创建
cache.put(key, pendingGenerationMarker);
// break 跳出循环已进入创建过程
break;
} while (true);
}
动态创建代理类的类对象。
// 动态地生成代 理类的字节码数组
byte[] proxyClassFile = ProxyGenerator.generateProxyClass( proxyName, interfaces);
try {
// 动态地定义新生成的代理类
proxyClass = defineClass0(loader, proxyName, proxyClassFile, 0,
proxyClassFile.length);
} catch (ClassFormatError e) {
throw new IllegalArgumentException(e.toString());
}
// 把生成的代理类的类对象记录进 proxyClasses 表
proxyClasses.put(proxyClass, null);
到了这里,其实generateProxyClass方法也是一个重点,但是generateProxyClass的方法代码跟踪不了,位于并未公开的 sun.misc 包,有若干常量、变量和方法以完成这个神奇的代码生成的过程,但是 sun 并没有提供源代码以供研读
synchronized (cache) {
if (proxyClass != null) {
cache.put(key, new WeakReference>(proxyClass));
} else {
cache.remove(key);
}
cache.notifyAll();
}
java.lang.reflect.InvocationHandler:这是调用处理器接口,它自定义了一个 invoke 方法,用于集中处理在动态代理类对象上的方法调用,通常在该方法中实现对委托类的代理访问。
Object invoke(Object proxy, Method method, Object[] args)
// 该方法负责集中处理动态代理类上的所 有方法调用。
//第一个参数既是代理类实例,
//第二个参数是被调用的方法对象
// 第三个方法是调用参数。调用处理器根据这三个参数进行预处理或分派到委托类实例上发射执行
每次生成动态代理类对象时都需要指定一个实现了该接口的调用处理器对象(参见 newProxyInstance 的第三个参数)。
很多人肯定跟我一样,我们在Handler中调用的method.invoke方法中并没有显示的调用invoke方法,只是在newProxyInstance中应用了一个handler对象,有了上面关于newProxyInstance的源码分析,我们知道了 newproxyinstance生成了一个$Proxy0类代理。当调用Subjectshow()方法时,其实调用的$Proxy0的SubjectShow()方法,从而调用父类Proxy中传进来第三个参数(h)的的Invoke方法。
//这个方法是 Proxy源码中的
protected Proxy(InvocationHandler h) {
this.h = h;
}
来看NewProxyInstance方法生成的$Proxy0代理类的源码
public final class $Proxy0 extends Proxy implements Subject {
private static Method m1;
private static Method m0;
private static Method m3;
private static Method m2;
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals",
new Class[] { Class.forName("java.lang.Object") });
m0 = Class.forName("java.lang.Object").getMethod("hashCode",
new Class[0]);
m3 = Class.forName("***.RealSubject").getMethod("request",
new Class[0]);
m2 = Class.forName("java.lang.Object").getMethod("toString",
new Class[0]);
} catch (NoSuchMethodException nosuchmethodexception) {
throw new NoSuchMethodError(nosuchmethodexception.getMessage());
} catch (ClassNotFoundException classnotfoundexception) {
throw new NoClassDefFoundError(classnotfoundexception.getMessage());
}
} //static
public $Proxy0(InvocationHandler invocationhandler) {
super(invocationhandler);
}
@Override
public final boolean equals(Object obj) {
try {
return ((Boolean) super.h.invoke(this, m1, new Object[] { obj })) .booleanValue();
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
@Override
public final int hashCode() {
try {
return ((Integer) super.h.invoke(this, m0, null)).intValue();
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
public final void SubjectShow() {
try {
super.h.invoke(this, m3, null); //就是这个地方 调用h.invoke()
return;
} catch (Error e) {
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
@Override
public final String toString() {
try {
return (String) super.h.invoke(this, m2, null);
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
}
从上面的$Proxy0中找到方法SubjectSHow()方法,我们可以看到中间调用了父类Proxy的参数Handler h的invoke方法,也就调用了ProxyHandler中的invoke()方法,还可以看到¥Proxy0还代理了equals()、hashcode()、tostring()这三个方法,至此动态代理实现机制就很清楚了