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

1 篇文章 0 订阅
代理是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制对某个对象的访问,动态代理使得开发人员无需手工编写代理类便可动态地获得代理类,下面就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实现对父类方法拦截
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值