动态代理与CGlib代理实现

一、原理区别:

java动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。

而CGlib代理是利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。

1、如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP 
2、如果目标对象实现了接口,可以强制使用CGLIB实现AOP 

3、如果目标对象没有实现接口,必须采用CGLIB库,spring会自动在JDK动态代理和CGLIB之间转换

如何强制使用CGLIB实现AOP?
 (1)添加CGLIB库,SPRING_HOME/cglib/*.jar
 (2)在spring配置文件中加入<aop:aspectj-autoproxy proxy-target-class=”true”/>

JDK动态代理和CGLIB字节码生成的区别?
 (1)JDK动态代理只能对实现了接口的类生成代理,而不能针对类
 (2)CGlib是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法 因为是继承,所以该类或方法最好不要声明成final 

二、代码实现

package com.spring.service;
//接口
public interface UserService {
	
	void save();
	void update();
	void delete();
	void find();
	
}
package com.spring.service.impl;

import com.spring.service.UserService;
//实现类
public class UserServiceImpl implements UserService{

	@Override
	public void save() {
		System.out.println("保存用户");
	}

	@Override
	public void update() {
		System.out.println("修改用户");
	}

	@Override
	public void delete() {
		System.out.println("删除用户");
	}

	@Override
	public void find() {
		System.out.println("查找用户");
	}

	
}
package com.spring.proxy;

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

import com.spring.service.UserService;
import com.spring.service.impl.UserServiceImpl;
//动态代理
public class UserServiceProxyFactory {

	private UserService userService;//需要代理的目标对象
	public UserService getUserService(UserService userService) {
		this.userService = userService;
		//ClassLoader loader:指定当前目标对象使用类加载器,写法固定
		//Class<?>[] interfaces:目标对象实现的接口的类型,写法固定
		//InvocationHandler h:事件处理接口,需传入一个实现类,一般直接使用匿名内部类
		UserService usProxy = (UserService) Proxy.newProxyInstance(UserServiceImpl.class.getClassLoader(),
				UserServiceImpl.class.getInterfaces(),
				new InvocationHandler() {
					@Override
					public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
						System.out.println("动态代理开启事务");
						Object invoke = method.invoke(userService, args);
						System.out.println("动态代理提交事务");
						return invoke;
					}
				}
				);
		return usProxy;
	}
}
package com.spring.proxy;

import java.lang.reflect.Method;

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import com.spring.service.UserService;
import com.spring.service.impl.UserServiceImpl;
//CGlib代理
public class UserServiceCGlibProxyFactory implements MethodInterceptor{

	private UserService userService;//需要代理的目标对象
	public UserService getUserService(UserService userService) {
		this.userService = userService;
		Enhancer enhancer = new Enhancer();//帮我们生成代理对象
		enhancer.setSuperclass(UserServiceImpl.class);//设置对谁进行代理
		enhancer.setCallback(this);//设置回调函数,代理要做什么
		userService = (UserService) enhancer.create();//创建代理对象
		return userService;
		
	}
	@Override
	public Object intercept(Object object, Method method, Object[] arg, MethodProxy proxy) throws Throwable {
		System.out.println("CGlib代理开启事务");
		Object invoke = method.invoke(userService, arg);
		System.out.println("CGlib代理提交事务");
		return invoke;
	}
}

package com.spring.test;
import org.junit.Test;

import com.spring.proxy.UserServiceCGlibProxyFactory;
import com.spring.proxy.UserServiceProxyFactory;
import com.spring.service.UserService;
import com.spring.service.impl.UserServiceImpl;

public class Demo {
	//测试动态代理
	@Test
	public void test1() {
		UserService userService = new UserServiceImpl();
		UserServiceProxyFactory factory = new UserServiceProxyFactory();
		UserService userProxy = factory.getUserService(userService);
		userProxy.save();
	}
	
	//测试CGlib代理
		@Test
		public void test2() {
			UserService userService = new UserServiceImpl();
			UserServiceCGlibProxyFactory factory = new UserServiceCGlibProxyFactory();
			UserService userProxy = factory.getUserService(userService);
			userProxy.save();
		}
}	

三、测试结果:

动态代理:
CGlib代理:

注意:

JDK动态代理不需要第三方的库,只要JDK环境就可以进行代理,但它有几个要求:
* 实现InvocationHandler 或者直接new InvocationHandler()
* 使用Proxy.newProxyInstance产生代理对象
* 被代理的对象必须要实现接口

CGLib 必须依赖于CGLib的类库,它通过继承类实现代理。

但是针对接口编程的环境下推荐使用JDK的代理。

Hibernate中的拦截器,其实现考虑到不需要其他接口,所以Hibernate中的相关代理采用的是CGLib来执行。

springAOP会自动在JDK动态代理和CGlib之间转换

发布了42 篇原创文章 · 获赞 15 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/guanripeng/article/details/79919608