代理是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制对某个对象的访问,动态代理使得开发人员无需手工编写代理类便可动态地获得代理类,下面就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实现对父类方法拦截
分享到:
相关推荐
在Java开发中,动态代理和CGLIB代理是两种常见的面向切面编程(AOP)实现方式,它们都用于在不修改原有代码的情况下,增强或扩展对象的功能。本篇文章将深入探讨JDK动态代理和CGLIB代理的区别,以及它们在实际应用中...
在 Spring AOP 框架中,默认情况下,Spring 会选择使用 JDK 动态代理,但是如果目标对象没有实现接口,Spring 就会选择使用 CGLIB 动态代理。这种机制可以确保 Spring AOP 框架可以代理任何类型的对象,无论它是否...
本文将深入探讨两种主要的Java代理实现:JDK动态代理和CGLIB代理。 一、JDK动态代理 JDK动态代理基于接口实现,它要求被代理的类必须实现至少一个接口。在运行时,Java会动态地创建一个新的类,这个类实现了与原始...
JDK动态代理和CGLIB代理是两种常用的实现方式。 首先,我们来看看JDK动态代理。JDK动态代理主要通过`java.lang.reflect.Proxy`类和`java.lang.reflect.InvocationHandler`接口来实现。Proxy类用于创建一个代理对象...
- **CGLIB代理**适用于目标类没有接口或者不希望修改原有接口的情况,其性能通常优于JDK代理,因为它是基于字节码生成的子类,而JDK代理需要反射调用接口方法。 在实际开发中,如Spring AOP框架就同时支持JDK和...
Spring框架是AOP实现的一个典范,它提供了两种主要的动态代理方式:JDK动态代理和CGLib动态代理。 **JDK动态代理**: JDK动态代理基于Java的反射API实现,适用于接口代理。当目标对象实现了至少一个接口时,Spring...
JDK动态代理和CGlib动态代理是Java中实现这一目标的两种主要方式。 ### JDK动态代理 JDK动态代理基于Java的接口实现。如果一个类实现了至少一个接口,我们就可以为这个类创建一个动态代理。动态代理通过`java.lang....
当JDK动态代理无法满足需求,例如代理的目标类没有实现接口时,CGLIB就能派上用场。CGLIB是一个强大的高性能的代码生成库,它可以在运行期扩展Java类与实现Java接口。CGLIB通过生成子类并在子类的方法上织入增强代码...
- **灵活性**:JDK代理要求目标类实现接口,而Cglib无此限制。 - **使用场景**:如果目标类已经实现了接口,且不关心性能,优先选择JDK代理;否则,Cglib是更好的选择。 在`DynamicProxyTest`源码中,我们可以看到...
在Java中,代理模式有多种实现方式,包括静态代理、JDK动态代理和CGLIB动态代理。 **静态代理** 静态代理是最早也是最基础的代理实现方式。在静态代理中,我们需要创建一个代理类,这个代理类与原始类(被代理类)...
Java 动态代理详解(代理模式+静态代理+JDK动态代理+CGLIB动态代理) Java 动态代理是 Java 编程语言中的一种强大工具,广泛应用于 Spring AOP、Hibernate 数据查询、测试框架的后端 mock、RPC 远程调用、Java 注解...
jdk 的动态代理和CGLIB代理
Java提供了两种主要的动态代理实现方式:JDK动态代理和CGLIB动态代理。 **JDK动态代理**: JDK动态代理基于接口实现,也就是说,被代理的对象必须实现至少一个接口。代理机制的核心是`java.lang.reflect.Proxy`类和...
以下是一个简单的CGLIB代理示例: ```java import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; public class CglibProxyExample ...
Cglib 动态代理的实现方式是:我们首先需要定义一个类,然后使用 Cglib 库来生成该类的代理对象,该代理对象将拦截对被代理对象的所有方法调用,并控制对被代理对象的访问。 Cglib 动态代理的优点是:它的实现方式...
3. **字节码生成**:CGLIB使用ASM库(一个Java字节码操控和分析框架)来生成和修改类的字节码,从而实现对目标类的动态代理。 **比较与选择** JDK动态代理简单易用,但仅限于代理实现接口的类。如果需要代理的类...
JDK代理和Cglib代理是两种常用的动态代理实现方式。 **JDK代理(Java Dynamic Proxy)** JDK动态代理是Java标准库提供的一种代理机制,位于`java.lang.reflect`包下的`Proxy`类和`InvocationHandler`接口。JDK代理...
CGLIB和JDK动态代理是两种常用的实现方式,它们各有优缺点,适用于不同的场景。下面将详细探讨这两种动态代理的区别。 首先,JDK动态代理主要依赖于`java.lang.reflect.Proxy`类和`java.lang.reflect....
- **JDK代理**:JDK动态代理使用反射和InvocationHandler接口生成一个实现了目标接口的新类。在运行时,这个新类的实例作为代理对象,它的方法调用都会转发到InvocationHandler的`invoke()`方法。 - **CGLIB代理**...