Java代理(jdk静态代理、动态代理和cglib动态代理)

一、代理是Java常用的设计模式,代理类通过调用被代理类的相关方法,并对相关方法进行增强。加入一些非业务性代码,比如事务、日志、报警发邮件等操作。

二、jdk静态代理

1、业务接口

/**
 * 业务接口
 * @author pc
 *
 */
public interface UserService {

	// 增加一个用户
	public void addUser();
	// 编辑账户
	public void editUser();

}

2、业务实现类

/**
 * 业务实现类
 * @author pc
 *
 */
public class UserServiceImpl implements UserService {

	public void addUser() {
		System.out.println("增加一个用户。。。");
	}

	public void editUser() {
		System.out.println("编辑一个用户。。。");
	}

}

3、代理类

/**
 * 代理类
 *
 * @author pc
 *
 */
public class UserServiceProxy implements UserService {

	private UserServiceImpl userImpl;

	public UserServiceProxy(UserServiceImpl countImpl) {
		this.userImpl = countImpl;
	}

	public void addUser() {
		System.out.println("代理类方法,进行了增强。。。");
		System.out.println("事务开始。。。");
		// 调用委托类的方法;
		userImpl.addUser();
		System.out.println("处理结束。。。");
	}

	public void editUser() {
		System.out.println("代理类方法,进行了增强。。。");
		System.out.println("事务开始。。。");
		// 调用委托类的方法;
		userImpl.editUser();
		System.out.println("事务结束。。。");
	}

}

  

4、测试类

public static void main(String[] args) {
	UserServiceImpl userImpl = new UserServiceImpl();
	UserServiceProxy proxy = new UserServiceProxy(userImpl);
	proxy.addUser();
	System.out.println("----------分割线----------");
	proxy.editUser();
}

5、结果

代理类方法,进行了增强。。。
事务开始。。。
增加一个用户。。。
处理结束。。。
----------分割线----------
代理类方法,进行了增强。。。
事务开始。。。
编辑一个用户。。。
事务结束。。。

  

三、jdk动态代理

1、业务接口

/**
 * 业务接口
 * @author pc
 *
 */
public interface UserService {

	// 增加一个用户
	public void addUser();
	// 编辑账户
	public void editUser();

}

2、业务接口实现类

/**
 * 业务接口实现类
 * @author pc
 *
 */
public class UserServiceImpl implements UserService {

	public void addUser() {
		System.out.println("增加一个用户。。。");
	}

	public void editUser() {
		System.out.println("编辑一个用户。。。");
	}
}

3、代理类

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

/**
 *
 * @author pc
 *
 */
public class ServiceInvocationHandler implements InvocationHandler {

	// 目标对象
	private Object target;

	public ServiceInvocationHandler(Object target) {
		super();
		this.target = target;
	}

	/**
	 * 创建代理实例
	 * @return
	 * @throws Throwable
	 */
	public Object getProxy() throws Throwable {
		return Proxy.newProxyInstance(Thread.currentThread()
				.getContextClassLoader(), this.target.getClass()
				.getInterfaces(), this);
		// 这样写只返回了目标对象,没有生成代理对象。
        // return target;
	}

	/**
	 * 实现InvocationHandler接口方法
	 * 执行目标对象的方法,并进行增强
	 */
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		Object result = null;
		System.out.println("代理类方法,进行了增强。。。");
		System.out.println("事务开始。。。");
		// 执行目标方法对象
		result = method.invoke(target, args);
		System.out.println("事务结束。。。");
		return result;
	}

}

  

4、测试类

public class Test {
	/**
	 * jdk动态代理会生成一个动态代理类,生成相应的字节码,然后通过ClassLoader加载字节码。
	 * 该实例继承了Proxy类,并实现了业务接口,在实现的方法里通过反射调用了InvocationHandler接口实现类
	 * 的invoke()回调方法。
	 * @param args
	 * @throws Throwable
	 */
	public static void main(String[] args) throws Throwable {
		UserService userService = new UserServiceImpl();
		ServiceInvocationHandler handler = new ServiceInvocationHandler(userService);
		// 根据目标生成代理对象
		UserService proxy = (UserService) handler.getProxy();
		proxy.addUser();
//		proxy.editUser();

	}

}

5、测试结果

代理类方法,进行了增强。。。
事务开始。。。
增加一个用户。。。
事务结束。。。

  

四、cglib动态代理

需要引入cglib的jar包,

在pom.xml加入依赖:

<!-- https://mvnrepository.com/artifact/cglib/cglib -->
<dependency>
	<groupId>cglib</groupId>
	<artifactId>cglib</artifactId>
	<version>2.2.2</version>
</dependency>

  

1、业务类,没有实现接口

/**
 * 业务类
 * 没有实现接口
 * 如果类是final的,则没法生成代理对象,报错。
 * 如果方法是final的,代理无效
 * @author pc
 *
 */
public class UserServiceImpl {

	public void addUser() {
		System.out.println("增加一个用户。。。");
	}

	public void editUser() {
		System.out.println("编辑一个用户。。。");
	}
}

2、代理类

import java.lang.reflect.Method;

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

/**
 * 使用Cglib动态代理
 * @author pc
 *
 */
public class UserServiceCglib implements MethodInterceptor{

	private Object target;

	/**
	 * 创建代理实例
	 * @param target
	 * @return
	 */
	public Object getInstance(Object target){
		this.target = target;
		Enhancer enhancer = new Enhancer();
		enhancer.setSuperclass(this.target.getClass());
		// 设置回调方法
		enhancer.setCallback(this);
		// 创建代理对象
		return enhancer.create();
	}

	/**
	 * 实现MethodInterceptor接口要重写的方法。
	 * 回调方法
	 */
	public Object intercept(Object obj, Method method, Object[] args,
			MethodProxy proxy) throws Throwable {
        System.out.println("事务开始。。。");
        Object result = proxy.invokeSuper(obj, args);
        System.out.println("事务结束。。。");
        return result;
	}

}

  

3、测试类

public class TestCglib {

	public static void main(String[] args) {
		UserServiceCglib cglib = new UserServiceCglib();
		UserServiceImpl bookFacadeImpl = (UserServiceImpl)cglib.getInstance(new UserServiceImpl());
		bookFacadeImpl.addUser();
//		bookFacadeImpl.editUser();
	}
}

4、结果:

事务开始。。。
增加一个用户。。。
事务结束。。。

5、如果业务实现类被定义成final类,就会报以下错误

Exception in thread "main" java.lang.IllegalArgumentException: Cannot subclass final class class cn.xx.xx.cgilb.UserServiceImpl
	at net.sf.cglib.proxy.Enhancer.generateClass(Enhancer.java:446)
	at net.sf.cglib.core.DefaultGeneratorStrategy.generate(DefaultGeneratorStrategy.java:25)
	at net.sf.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:216)
	at net.sf.cglib.proxy.Enhancer.createHelper(Enhancer.java:377)
	at net.sf.cglib.proxy.Enhancer.create(Enhancer.java:285)
	at cn.pconline.proxy.cgilb.UserServiceCglib.getInstance(UserServiceCglib.java:30)
	at cn.pconline.proxy.cgilb.TestCglib.main(TestCglib.java:7)

五、总结

1、原理

jdk静态代理实现比较简单,一般是直接代理对象直接包装了被代理对象。

  jdk动态代理是接口代理,被代理类A需要实现业务接口,业务代理类B需要实现InvocationHandler接口。

jdk动态代理会根据被代理对象生成一个继承了Proxy类,并实现了该业务接口的jdk代理类,该类的字节码会被传进去的ClassLoader加载,创建了jdk代理对象实例,

jdk代理对象实例在创建时,业务代理对象实例会被赋值给Proxy类,jdk代理对象实例也就有了业务代理对象实例,同时jdk代理对象实例通过反射根据被代理类的业务方法创建了相应的Method对象m(可能有多个)。当jdk代理对象实例调用业务方法,如proxy.addUser();这个会先把对应的m对象作为参数传给invoke()方法(就是invoke方法的第二个参数),调用了jdk代理对象实例的invoke()回调方法,在invoke方法里面再通过反射来调用被代理对象的因为方法,即result = method.invoke(target, args);。

cglib动态代理是继承代理,通过ASM字节码框架修改字节码生成新的子类,重写并增强方法的功能。

2、优缺点

jdk静态代理类只能为一个被代理类服务,如果需要代理的类比较多,那么会产生过多的代理类。jdk静态代理在编译时产生class文件,运行时无需产生,可直接使用,效率好。

jdk动态代理必须实现接口,通过反射来动态代理方法,消耗系统性能。但是无需产生过多的代理类,避免了重复代码的产生,系统更加灵活。

cglib动态代理无需实现接口,通过生成子类字节码来实现,比反射快一点,没有性能问题。但是由于cglib会继承被代理类,需要重写被代理方法,所以被代理类不能是final类,被代理方法不能是final。

因此,cglib的应用更加广泛一点。

参考:http://blog.csdn.net/fighterandknight/article/details/51200470

http://blog.csdn.net/jiankunking/article/details/52143504

时间: 2024-08-28 14:29:22

Java代理(jdk静态代理、动态代理和cglib动态代理)的相关文章

关于JDK动态代理和CGLIB动态代理

1. 代理模式 一句话总结:为其他对象提供一种代理以控制对这个对象的访问.千篇一律的介绍:代理模式是常用的java设计模式,他的特征是代理类与委托类(或目标类)有同样的接口,代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类,以及事后处理消息等.代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务. 按照代理的创建时期,代理类可以分为两种. 静态代理:由程序员创建或特定工具

spring aop原理 JDK动态代理和CGLIB动态代理

Spring的两大特性是IOC和AOPIOC负责将对象动态的注入到容器,从而达到一种需要谁就注入谁,什么时候需要就什么时候注入的效果.理解spring的ioc也很重要.但是今天主要来和大家讲讲aop.AOP 广泛应用于处理一些具有横切性质的系统级服务,AOP 的出现是对 OOP 的良好补充,用于处理系统中分布于各个模块的横切关注点,比如事务管理.日志.缓存等等. AOP实现的关键在于AOP框架自动创建的AOP代理.AOP代理主要分为静态代理和动态代理, 静态代理的代表为AspectJ:动态代理则

jdk动态代理和cglib动态代理底层实现原理详细解析(cglib动态代理篇)

代理模式是一种很常见的模式,关于底层原理网上看到很多的有关的讲解,但看了一些都觉得比较粗略,很多时候把底层代码copy下来也不大讲解,感觉不如自己详细的写上一篇.本文将以非常详细的说明来分析cglib动态代理底层的实现原理,篇幅较长,但是每个核心方法代码中每步都有说明.还请耐心阅读 1. 举例 使用cglib代理需要引入两个包,maven的话包引入如下 <!-- https://mvnrepository.com/artifact/cglib/cglib --> <dependency&

深入探索spring技术内幕(六): JDK动态代理和cglib生成代理

[ JDK生成代理 ] JDK中给我们提供了一个Proxy类可以动态的给我们生成代理. 假定我们要做一个权限管理系统, 需要控制用户对某一个方法的访问. 如果user为null, 那么不让用户访问save方法. ① 接口类: PersonService public interface PersonService { public void save(); } ② 实现类: PersonServiceImpl public class PersonServiceImpl implements P

JDK动态代理和CGLIB动态代理

转载自http://www.itzhai.com/java-dong-tai-dai-li-zhi-jdk-dong-tai-dai-li-he-cglib-dong-tai-dai-li-mian-xiang-qie-mian-bian-cheng-aop-yuan-li.html 静态代理 静态代理相对来说比较简单,无非就是聚合+多态: 参考:设计模式笔记 – Proxy 代理模式 (Design Pattern) 动态代理 我们知道,通过使用代理,可以在被代理的类的方法的前后添加一些处理方

JDK动态代理和CGLIB动态代理+源码下载

在上一篇文章-java代理详解讲解实现机制,一种是继承另外一种是组合,而且通过做实现也证明使用组合的方式更加的灵活.之后提到了代理的两种种类,一种是静态代理,另外一种是动态代理.上一篇文件中着重介绍的是静态代理(相对于动态代理很容易理解).这一片文章就接着介绍动态代理. 动态代理实现的最终效果:通过以一个统一的方式实现对任意的接口/类的代理.相比较静态代理而言,我们可以不用再无限制的增加代理类,不用再写许多重复的代码.很符合面向对象设计原则中的"开闭原则":对修改关闭,对扩展开放. 动

【Spring】AOP之JDK动态代理和CGLib动态代理

林炳文Evankaka原创作品.转载请注明出处http://blog.csdn.net/evankaka 一.JAVA动态代理  1.1 代理模式         代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类,以及事后处理消息等.代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务. 按照代理的创

jdk动态代理和cglib动态代理的区别

CGLIB代理: CGLIB底层:使用字节码处理框架ASM,来转换字节码并生成新的类. CGLIB(CODE GENERLIZE LIBRARY)代理是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的所有方法,所以该类或方法不能声明称final的. 如果目标对象实现了接口,可以强制使用CGLIB实现代理. 如果目标对象没有实现接口,则默认会采用CGLIB代理: 为什么jdk动态代理必须基于接口 原因如下: 1.生成的代理类继承了Proxy,由于java是单继承,所以只能实现接口,通过接口

[z]Java代理(jdk静态代理、动态代理和cglib动态代理)

一.代理是Java常用的设计模式,代理类通过调用被代理类的相关方法,并对相关方法进行增强.加入一些非业务性代码,比如事务.日志.报警发邮件等操作. 二.jdk静态代理 1.业务接口 1 2 3 4 5 6 7 8 9 10 11 12 13 /**  * 业务接口  * @author pc  *  */ public interface UserService {          // 增加一个用户     public void addUser();     // 编辑账户     pub