`
随心而行
  • 浏览: 13876 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

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实现对父类方法拦截
分享到:
评论

相关推荐

    浅谈JDK动态代理与CGLIB代理去区别

    在Java开发中,动态代理和CGLIB代理是两种常见的面向切面编程(AOP)实现方式,它们都用于在不修改原有代码的情况下,增强或扩展对象的功能。本篇文章将深入探讨JDK动态代理和CGLIB代理的区别,以及它们在实际应用中...

    Spring框架中JDK动态代理和cglib动态代理

    在 Spring AOP 框架中,默认情况下,Spring 会选择使用 JDK 动态代理,但是如果目标对象没有实现接口,Spring 就会选择使用 CGLIB 动态代理。这种机制可以确保 Spring AOP 框架可以代理任何类型的对象,无论它是否...

    java代理机制 JDK动态代理和cglib代理 详解

    本文将深入探讨两种主要的Java代理实现:JDK动态代理和CGLIB代理。 一、JDK动态代理 JDK动态代理基于接口实现,它要求被代理的类必须实现至少一个接口。在运行时,Java会动态地创建一个新的类,这个类实现了与原始...

    JDK动态代理和CGLIB代理

    JDK动态代理和CGLIB代理是两种常用的实现方式。 首先,我们来看看JDK动态代理。JDK动态代理主要通过`java.lang.reflect.Proxy`类和`java.lang.reflect.InvocationHandler`接口来实现。Proxy类用于创建一个代理对象...

    Jdk动态代理和cglib动态代理原理

    - **CGLIB代理**适用于目标类没有接口或者不希望修改原有接口的情况,其性能通常优于JDK代理,因为它是基于字节码生成的子类,而JDK代理需要反射调用接口方法。 在实际开发中,如Spring AOP框架就同时支持JDK和...

    AOP之JDK动态代理和CGLib动态代理

    Spring框架是AOP实现的一个典范,它提供了两种主要的动态代理方式:JDK动态代理和CGLib动态代理。 **JDK动态代理**: JDK动态代理基于Java的反射API实现,适用于接口代理。当目标对象实现了至少一个接口时,Spring...

    jdk动态代理和CGlib动态代理

    JDK动态代理和CGlib动态代理是Java中实现这一目标的两种主要方式。 ### JDK动态代理 JDK动态代理基于Java的接口实现。如果一个类实现了至少一个接口,我们就可以为这个类创建一个动态代理。动态代理通过`java.lang....

    Jdk动态代理,cglib动态代理,反射和拦截器(链)示例

    当JDK动态代理无法满足需求,例如代理的目标类没有实现接口时,CGLIB就能派上用场。CGLIB是一个强大的高性能的代码生成库,它可以在运行期扩展Java类与实现Java接口。CGLIB通过生成子类并在子类的方法上织入增强代码...

    JDK动态代理和Cglib动态代理实例源码

    - **灵活性**:JDK代理要求目标类实现接口,而Cglib无此限制。 - **使用场景**:如果目标类已经实现了接口,且不关心性能,优先选择JDK代理;否则,Cglib是更好的选择。 在`DynamicProxyTest`源码中,我们可以看到...

    代理模式-静态动态代理-jdk动态代理-cglib动态代理

    在Java中,代理模式有多种实现方式,包括静态代理、JDK动态代理和CGLIB动态代理。 **静态代理** 静态代理是最早也是最基础的代理实现方式。在静态代理中,我们需要创建一个代理类,这个代理类与原始类(被代理类)...

    Java 动态代理详解(代理模式+静态代理+JDK动态代理+CGLIB动态代理)

    Java 动态代理详解(代理模式+静态代理+JDK动态代理+CGLIB动态代理) Java 动态代理是 Java 编程语言中的一种强大工具,广泛应用于 Spring AOP、Hibernate 数据查询、测试框架的后端 mock、RPC 远程调用、Java 注解...

    jdk 的动态代理和CGLIB代理

    jdk 的动态代理和CGLIB代理

    JAVA动态代理实现Demo(JDK动态代理和CGLIB动态代理)

    Java提供了两种主要的动态代理实现方式:JDK动态代理和CGLIB动态代理。 **JDK动态代理**: JDK动态代理基于接口实现,也就是说,被代理的对象必须实现至少一个接口。代理机制的核心是`java.lang.reflect.Proxy`类和...

    java动态代理实例(jdk动态代理和cglib)

    以下是一个简单的CGLIB代理示例: ```java import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; public class CglibProxyExample ...

    静态代理、jdk动态代理、cglib动态代理

    Cglib 动态代理的实现方式是:我们首先需要定义一个类,然后使用 Cglib 库来生成该类的代理对象,该代理对象将拦截对被代理对象的所有方法调用,并控制对被代理对象的访问。 Cglib 动态代理的优点是:它的实现方式...

    jdk动态代理 cglib3.0动态代理

    3. **字节码生成**:CGLIB使用ASM库(一个Java字节码操控和分析框架)来生成和修改类的字节码,从而实现对目标类的动态代理。 **比较与选择** JDK动态代理简单易用,但仅限于代理实现接口的类。如果需要代理的类...

    JDK代理和Cglib代理

    JDK代理和Cglib代理是两种常用的动态代理实现方式。 **JDK代理(Java Dynamic Proxy)** JDK动态代理是Java标准库提供的一种代理机制,位于`java.lang.reflect`包下的`Proxy`类和`InvocationHandler`接口。JDK代理...

    CGLIB 和 JDK生成动态代理类的区别

    CGLIB和JDK动态代理是两种常用的实现方式,它们各有优缺点,适用于不同的场景。下面将详细探讨这两种动态代理的区别。 首先,JDK动态代理主要依赖于`java.lang.reflect.Proxy`类和`java.lang.reflect....

    jdk与cglib动态代理与底层实现

    - **JDK代理**:JDK动态代理使用反射和InvocationHandler接口生成一个实现了目标接口的新类。在运行时,这个新类的实例作为代理对象,它的方法调用都会转发到InvocationHandler的`invoke()`方法。 - **CGLIB代理**...

Global site tag (gtag.js) - Google Analytics