您的位置:首页 > 编程语言 > Java开发

Java 动态代理

2016-07-12 00:00 232 查看
#Java 动态代理

##1.代理模式
首先了解下设计模式中的代理模式
定义:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
UML类图:



代码:

//Subject
public abstract class Subject {
public void methodA() {
}
public void methodB() {
}
}

//RealSubject
public class RealSubject extends Subject{

@Override
public void methodA() {
System.out.println("this is methodA");
}

@Override
public void methodB() {
System.out.println("this is methodB");
}
}

//Proxy
public class Proxy extends Subject{

private Subject subject;
public Proxy(Subject subject){
this.subject=subject;
}
@Override
public void methodA() {
System.out.println("before this methodA");
subject.methodA();
}

@Override
public void methodB() {
System.out.println("before this methodB");
subject.methodB();
}
}

//Main
public class Main {
public static void main(String[] args){
Proxy proxy =new Proxy(new RealSubject());
proxy.methodA();
proxy.methodB();
}
}

输出为:
before this methodA

this is methodA

before this methodB

this is methodB

##2.JDK动态代理

###2.1了解 java.lang.reflect.Proxy类

//代理类,它提供了一组静态方法来为一组接口动态地生成代理类及其对象。
//静态变量
//代理缓存
private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());

// newProxyInstance 该方法用于为指定类装载器、一组接口及调用处理器生成动态代理类实例
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)  throws IllegalArgumentException
{
Objects.requireNonNull(h);

final Class<?>[] intfs = interfaces.clone();
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
}

/*
* Look up or generate the designated proxy class.
*/
//生成代理class的地方
Class<?> cl = getProxyClass0(loader, intfs);

/*
* Invoke its constructor with the designated invocation handler.
*/

//利用反射,使用实现的InvocationHandler作为参数调用构造方法来获得代理类的实例
try {
if (sm != null) {
checkNewProxyPermission(Reflection.getCallerClass(), cl);
}

final Constructor<?> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
if (!Modifier.isPublic(cl.getModifiers())) {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
cons.setAccessible(true);
return null;
}
});
}
return cons.newInstance(new Object[]{h});
} catch (IllegalAccessException|InstantiationException e) {
throw new InternalError(e.toString(), e);
} catch (InvocationTargetException e) {
Throwable t = e.getCause();
if (t instanceof RuntimeException) {
throw (RuntimeException) t;
} else {
throw new InternalError(t.toString(), t);
}
} catch (NoSuchMethodException e) {
throw new InternalError(e.toString(), e);
}
}

// getProxyClass 该方法用于获得Proxy的Class对象
public static Class<?> getProxyClass(ClassLoader loader,Class<?>... interfaces)    throws IllegalArgumentException
{
//接口clone
final Class<?>[] intfs = interfaces.clone();
//安全管理器
final SecurityManager sm = System.getSecurityManager();
//检查能否获取Class对象
if (sm != null) {
checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
}
//调用 getProxyClass0方法
return getProxyClass0(loader, intfs);
}

// getProxyClass0

private static Class<?> getProxyClass0(ClassLoader loader,Class<?>... interfaces) {

//首先接口的数目不能超过 65535
if (interfaces.length > 65535) {
throw new IllegalArgumentException("interface limit exceeded");
}

// If the proxy class defined by the given loader implementing
// the given interfaces exists, this will simply return the cached copy;
// otherwise, it will create the proxy class via the ProxyClassFactory

//JDK对代理进行了缓存,如果已经存在相应的代理类,则直接返回,否则才会通过ProxyClassFactory来创建代理
return proxyClassCache.get(loader, interfaces);
}

//静态内部类
//ProxyClassFactory

private static final class ProxyClassFactory
implements BiFunction<ClassLoader, Class<?>[], Class<?>>
{
// 所有代理类名字的前缀
private static final String proxyClassNamePrefix = "$Proxy";

// 用于生成代理类名字的计数器
private static final AtomicLong nextUniqueNumber = new AtomicLong();

@Override
public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {

Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
for (Class<?> intf : interfaces) {
Class<?> interfaceClass = null;
try {
interfaceClass = Class.forName(intf.getName(), false, loader);
} catch (ClassNotFoundException e) {
}
if (interfaceClass != intf) {
throw new IllegalArgumentException(
intf + " is not visible from class loader");
}

if (!interfaceClass.isInterface()) {
throw new IllegalArgumentException(
interfaceClass.getName() + " is not an interface");
}
if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
throw new IllegalArgumentException(
"repeated interface: " + interfaceClass.getName());
}
}

String proxyPkg = null;     // package to define proxy class in
int accessFlags = Modifier.PUBLIC | Modifier.FINAL;

// 对于非公共接口,代理类的包名与接口的相同
for (Class<?> intf : interfaces) {
int flags = intf.getModifiers();
if (!Modifier.isPublic(flags)) {
accessFlags = Modifier.FINAL;
String name = intf.getName();
int n = name.lastIndexOf('.');
String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
if (proxyPkg == null) {
proxyPkg = pkg;
} else if (!pkg.equals(proxyPkg)) {
throw new IllegalArgumentException(
"non-public interfaces from different packages");
}
}
}

// 对于公共接口的包名,默认为com.sun.proxy
if (proxyPkg == null) {
proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
}

long num = nextUniqueNumber.getAndIncrement();
String proxyName = proxyPkg + proxyClassNamePrefix + num;

// 真正的生成代理类的字节码的地方
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces, accessFlags);
try {
// 根据二进制字节码返回相应的Class实例
return defineClass0(loader, proxyName,
proxyClassFile, 0, proxyClassFile.length);
} catch (ClassFormatError e)
throw new IllegalArgumentException(e.toString());
}
}
}

###2.2了解java.lang.reflect.InvocationHandler类

//处理器接口,自定义invoke方法,集中处理在动态代理对象上的调用,通常在该方法中实现对委托类的代理访问。
//第一个参数为动态代理对象,第二个参数为委托对象,第三个对象为调用参数。
public Object invoke(Object proxy, Method method, Object[] args)

###2.3代码实现

//HelloWord
public interface HelloWord {
public void sayHelloWorld();
}

//HelloWordImpl
public class HelloWordImpl implements HelloWord {
public void sayHelloWorld() {
System.out.println("HelloWorld!");
}
}

//HelloWorldHandler
public class HelloWorldHandler implements InvocationHandler {

// 要代理的原始对象
private Object obj;

public HelloWorldHandler(Object obj) {
super();
this.obj = obj;
}

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = null;
// 调用之前
doBefore();
// 调用原始对象的方法
result = method.invoke(obj, args);
// 调用之后
doAfter();
return result;
}

private void doBefore() {
System.out.println("before method invoke");
}

private void doAfter() {
System.out.println("after method invoke");
}
}

//Client
public class HelloWorldTest {
public static void main(String[] args) {
HelloWord helloWorld=new HelloWordImpl();
InvocationHandler handler=newHelloWorldHandler(helloWorld);

//创建动态代理对象
HelloWord proxy=(HelloWord)Proxy.newProxyInstance(
helloWorld.getClass().getClassLoader(),
helloWorld.getClass().getInterfaces(),
handler);
proxy.sayHelloWorld();
}
}

输出结果为:before method invoke

HelloWorld!

after method invoke

##3.CGLib动态代理

###3.1介绍:
CGLib是通过生成java字节码从而动态的产生代理对象,因此需要字节码解析处理的依赖asm类库,字节码动态生成的代理对象实际上是继承了真实委托类的。这种实现方式需要导入cglib和asm的类库。
###3.2原理:
通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用。
###3.2代码实现:

//Tiger
public class Tiger{

public void run() {
System.out.println("Tiger is running");
}
}

//CglibProxy

import java.lang.reflect.Method;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

public class CglibProxy implements MethodInterceptor {

public Object getProxyInstance(Class target) {
// 声明增强类实例
Enhancer enhancer = new Enhancer();
// 设置需要创建子类的类
enhancer.setSuperclass(target);
enhancer.setCallback(this);
// 通过字节码技术动态创建子类实例
return enhancer.create();
}

public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("before");
proxy.invokeSuper(obj, args);
System.out.println("after");
return null;
}
}

//Client
public class Client {

public static void main(String[] args) {
CglibProxy proxy = new CglibProxy();
Tiger tiger = (Tiger)proxy.getProxyInstance(Tiger.class);
tiger.run();
}
}

输出为:before

Tiger is running

after

##4.JDK动态代理和CgLib动态代理比较

* JDK动态代理对有实现接口的对象做代理

* CgLib动态代理对对没有实现接口的普通类做代理
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: