JDK动态代理及cglib动态代理实现分析

本文详细解析了JDK动态代理和CGLIB动态代理的工作原理及实现过程,通过具体示例展示了如何利用这两种方式为对象生成代理类。
代理是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制对某个对象的访问,动态代理使得开发人员无需手工编写代理类便可动态地获得代理类,下面就JDK动态代理与CGLIB动态代理展开分析。

一、JDK动态代理分析
JDK动态代理依靠接口实现,所以仅支持实现了接口的动态代理,下面用一个常用的JDK动态代理实现进行分析
(1)实现InvocationHandler实现调用处理器

package com.qerooy.handler;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

import org.apache.log4j.Logger;

/**
* 动态代理类调用处理器
*/
public class InvocationHandlerImpl implements InvocationHandler {

private Object target; //需代理的目录对象

public InvocationHandlerImpl(Object target){
this.target = target;
}

Logger log = Logger.getLogger(getClass());

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
log.info("InvocationHandlerImpl invoke start");
Object obj = method.invoke(target, args);
log.info("InvocationHandlerImpl invoke end");
return obj;
}

/**
* 获取代理对象
* @param obj
* @return
*/
public Object get(Object obj){
return java.lang.reflect.Proxy.newProxyInstance(obj.getClass().getClassLoader(),
obj.getClass().getInterfaces(), this);

}

}

(2)定义UserService接口,并实现此接口UserServiceImpl

package com.qerooy.service;

public interface UserService {

public void saveUser();

}


package com.qerooy.service.impl;

import org.apache.log4j.Logger;

import com.qerooy.service.UserService;

public class UserServiceImpl implements UserService {

Logger log = Logger.getLogger(getClass());

public void saveUser() {
log.info("this is saveUser");
}

}

(3)编写一个测试类进行测试

package com.qerooy;

import org.apache.log4j.Logger;
import org.junit.Test;

import com.qerooy.handler.InvocationHandlerImpl;
import com.qerooy.service.UserService;
import com.qerooy.service.impl.UserServiceImpl;

public class JDKDynamicProxyTest {

Logger log = Logger.getLogger(getClass());

@Test
public void test(){
UserService userService = new UserServiceImpl();
InvocationHandlerImpl handler = new InvocationHandlerImpl(userService);
UserService service = (UserService)handler.get(userService);
service.saveUser();

log.info("生成的代理类名称:"+service.getClass().getName());
log.info("test is ok");
}

}


运行可得结果
INFO InvocationHandlerImpl invoke start
INFO this is saveUser
INFO InvocationHandlerImpl invoke end
INFO 生成的代理类名称:$Proxy4
INFO test is ok

至此JDK动态代理实现完成。
可以看到动态代理类是由java.lang.reflect.Proxy.newProxyInstance生成的,那么Proxy到底为我们生成了什么样的代理类呢?接下来通过源代码来了解一下Proxy到底是如何实现的,JDK的安装目录中均有源码src.zip。
关键代码

public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException {
// ... 省略
//此处为生成代理类关键代码
Class cl = getProxyClass(loader, interfaces);
// ...省略
Constructor cons = cl.getConstructor(constructorParams);
return (Object) cons.newInstance(new Object[] { h });
// ...省略
}


public static Class<?> getProxyClass(ClassLoader loader, Class<?>... interfaces) throws IllegalArgumentException {
// ... 省略
//此处为生成动态代理类的字节码,由defineClass0进行装载
//所以我们可以用此方法生成代理类,将其反编译查看
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(proxyName, interfaces);
// ... 省略
}



由上可以看到生成代理类的方法,所以在Test类中将代理类生成,Test类改为

package com.qerooy;

import java.io.FileOutputStream;
import java.io.IOException;

import org.apache.log4j.Logger;
import org.junit.Test;

import sun.misc.ProxyGenerator;

import com.qerooy.handler.InvocationHandlerImpl;
import com.qerooy.service.UserService;
import com.qerooy.service.impl.UserServiceImpl;

public class JDKDynamicProxyTest {

Logger log = Logger.getLogger(getClass());

@Test
public void test(){
UserService userService = new UserServiceImpl();
InvocationHandlerImpl handler = new InvocationHandlerImpl(userService);
UserService service = (UserService)handler.get(userService);
service.saveUser();

log.info(service.getClass().getName());
log.info("test is ok");
//将生成的动态代理类保存到文件
writeClassFile("c:/",service.getClass().getName(),userService.getClass().getInterfaces());
}

public static void writeClassFile(String path,String className,Class<?>[] clazz){
//获取代理类的字节码
byte[] classFile = ProxyGenerator.generateProxyClass(className,clazz);
FileOutputStream out = null;
try{
out = new FileOutputStream(path+className+".class");
out.write(classFile);
out.flush();
}catch(Exception e){
e.printStackTrace();
}finally{
try{
out.close();
}catch(IOException e){
e.printStackTrace();
}
}
}

}


在C盘根目录下生成了动态的代理类class,使用反编译工具查看关键代码如下

public final class $Proxy4 extends Proxy implements UserService
{

public $Proxy4(InvocationHandler paramInvocationHandler)
throws
{
super(paramInvocationHandler);
}

public final void saveUser() throws
{
// ... 省略
this.h.invoke(this, m3, null);//此处使用调用器方法并将方法名传回
// ... 省略
}
}


可以看到,生成的代理类继承了Proxy类并实现了UserService接口,而实现接口的方法中使用调用处理器的方法,处理器h则在构造方法中传入了return (Object) cons.newInstance(new Object[] { h }); 即生成的代理类中调用了InvocationHandler方法。

简单来说生成的代理类中,每一个实现接口的方法均调用InvocationHandler的方法invoke,完成代理的逻辑。

二、CGLIB动态代理分析
JDK动态代理只能代理实现了接口的类,若需代理的类未实现任何接口,则需要使用CGLIB生成代理类
同样首先由简单的实现进行分析
(1)编写一个未实现任何接口的类AccountServiceImpl

package com.qerooy.service.impl;
import org.apache.log4j.Logger;
public class AccountServiceImpl{
Logger log = Logger.getLogger(getClass());

public void saveAccount() {
log.info("this is saveAccount");
}
}

(2)创建类MethodInterceptorImpl实现了CGLIB方法拦截器接口MethodInterceptor

package com.qerooy.interceptor;
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import org.apache.log4j.Logger;
public class MethodInterceptorImpl implements MethodInterceptor{
Logger log = Logger.getLogger(getClass());

@Override
public Object intercept(Object proxy, Method method, Object[] params, MethodProxy methodProxy) throws Throwable {
log.info("MethodInterceptorImpl invoke start");
Object object = methodProxy.invokeSuper(proxy, params);
log.info("MethodInterceptorImpl invoke end");
return object;
}

/**
* 获取代理对象
* @param obj
* @return
*/
public Object get(Class clazz){
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(clazz); //设置代理目标
enhancer.setCallback(this); //设置回调
enhancer.setClassLoader(clazz.getClassLoader());
return enhancer.create();
}
}

(3)编写一个测试类

package com.qerooy;
import org.apache.log4j.Logger;
import org.junit.Test;
import com.qerooy.interceptor.MethodInterceptorImpl;
import com.qerooy.service.impl.AccountServiceImpl;
public class CGLIBDynamicProxyTest {
Logger log = Logger.getLogger(getClass());

@Test
public void test(){
MethodInterceptorImpl interceptor = new MethodInterceptorImpl();

AccountServiceImpl service = (AccountServiceImpl)interceptor.get(AccountServiceImpl.class);
log.info(service.getClass().getName());
service.saveAccount();


log.info("test is ok");
}
}

运行结果如下
INFO MethodInterceptorImpl invoke start
INFO this is saveAccount
INFO MethodInterceptorImpl invoke end
INFO test is ok

可以看到,同样实现了动态代理。由于篇幅问题,后面介绍CGlib实现对父类方法拦截
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值