静态代理与JDK、CGLib动态代理

一、代理模式

代理模式概述

代理模式是设计模式之一,代理模式中存在代理者和被代理者,代理者和被代理者都具有相同的功能,并且代理者执行功能时会附加一些额外的操作。符合开闭原则,不用修改被代理者任何的代码,就能扩展新的功能。

分类

代理分为静态代理和动态代理

静态代理

静态代理是字节码一上来就创建好,并完成加载。

1.代理者和被代理者都实现了相同的接口(或继承相同的父类)

2.代理者包含了一个被代理者的对象

3.调用功能时,代理者会调用被代理者的功能,同时附加新的操作动态代理

动态代理

字节码随用随创建,随用随加载。不修改源码的基础上对方法增强

动态代理又分为:JDK动态代理和CGLib动态代理

	区别是:
	JDK动态代理的被代理者必须实现任意接口
	
	CGLib动态代理不用实现接口,是通过继承实现的

二、静态代理

1.准备被代理的类

public interface IUserService {
	
	void save();
	
	void select(Long id);
}

public class UserService implements IUserService {
	
	@Override
	public void save() {
		System.out.println("save....");
	}
	
	@Override
	public void select(Long id) {
		System.out.println("select..."+id);
	}
}

2.编写静态代理

public class StaticProxy implements IUserService {
	
	UserService userService;
	
	public StaticProxy(UserService userService){
		this.userService=userService;
	}
	
	@Override
	public void save() {
		System.out.println("开始执行save()方法....");
		userService.save();
		System.out.println("save()方法执行结束....");
	}
	
	
	@Override
	public void select(Long id) {
	
	}
}

3.执行测试

public class StaticProxyTest {
	
	@Test
	public  void test(){
		
		UserService userService = new UserService();
		StaticProxy staticProxy = new StaticProxy(userService);
		staticProxy.save();
	}
}

在这里插入图片描述

三、基于接口的JDK动态代理

使用JDK 官方的 Proxy 类。要求被代理类最少实现一个接口。

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

需要指定一个类加载器,然后生成的代理对象实现类的接口或类的类型,接着处理额外功能

1.准备被代理的类

public interface IUserService {
	
	void save();
	
	void select(Long id);
}

public class UserService implements IUserService {
	
	@Override
	public void save() {
		System.out.println("save....");
	}
	
	@Override
	public void select(Long id) {
		System.out.println("select..."+id);
	}
}

2.编写基Proxy动态代理

方式一:

public class InterfaceProxy {
	
	final UserService userService=new UserService();
	
	/**
	 *  使用Proxy类中的newProxyInstance方法创建代理对象
	 *
	 *  创建代理对象的要求被代理类最少实现一个接口
	 *
	 *  newProxyInstance方法的参数:
	 *      ClassLoader:类加载器,用于加载代理对象字节码。和被代理对象使用相同的类加载器。
	 *      Class[]:字节码数组,用于让代理对象和被代理对象有相同方法。
	 *      InvocationHandler:用于提供增强的代码,写如何代理。一般是写该接口的实现类,通常情况下都是匿名内部类,但不是必须的。
	 *
	 */
	IUserService iUserServiceProxy= (IUserService) Proxy.newProxyInstance(userService.getClass().getClassLoader(), UserService.class.getInterfaces(), new InvocationHandler() {
		/**
		 * 执行被代理对象的任何接口方法都会经过该方法
		 *
		 * @param proxy   代理对象的引用
		 * @param method  当前执行的方法
		 * @param args    当前执行方法所需的参数
		 * @return        和被代理对象方法有相同的返回值
		 * @throws Throwable
		 */
		@Override
		public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		
			System.out.println("-------------------------------");
			System.out.println("进入动态代理类。。。。。。。。");
			
			Object returnValue = null;
			
			//对select方法作增强
			if("select".equals(method.getName())) {
				//获取参数
				Long id = (Long) args[0];
				//让id+10
				id+=10;
				returnValue = method.invoke(userService, id);
			}
			return returnValue;
		}
	});
}

方式二:

public class InterfaceProxy implements InvocationHandler {
	
	private Object object;
	
	public InterfaceProxy(Object object) {
		this.object = object;
	}
	
	@Override
	public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
		System.out.println("-------------------------------");
		System.out.println("进入动态代理类。。。。。。。。");
		
		Object returnValue = null;
		
		//对select方法作增强
		if("select".equals(method.getName())) {
			//获取参数
			Long id = (Long) objects[0];
			//让id+10
			id+=10;
			returnValue = method.invoke(object, id);
		}
		return returnValue;
	}
}

3.执行测试

执行测试一:

public class ProxyTest {
	
	@Test
	public void Test(){
		
		InterfaceProxy interfaceProxy = new InterfaceProxy();
		
		//未代理
		interfaceProxy.userService.select(1L);
		
		//经过代理
		interfaceProxy.iUserServiceProxy.select(1L);
	}
}

在这里插入图片描述
执行测试二:

public class ProxyTest {
	
	@Test
	public void Test() {
		
			UserServiceuserService = new UserService();
			
			InterfaceProxy interfaceProxy = new InterfaceProxy(userService);
			
			IUserService iUserServiceProxy=	(IUserService) Proxy.newProxyInstance(userService.getClass().getClassLoader(), UserService.class.getInterfaces(),interfaceProxy);
			
			//未代理
			userService.select(1L);
			
			//经过代理
			iUserServiceProxy.select(1L);
		}
}

在这里插入图片描述

四、基于子类的CGLib动态代理

使用第三方的 CGLib。要求被代理类不能用 final 修饰。

Cglib是动态代理利用asm的开源包,对代理对象的Class文件加载进来,通过修改其字节码生成的子类来处理Cglib是基于继承父类生成的代理类.

1.准备被代理的类

public interface IUserService {
	
	void save();
	
	void select(Long id);
}

public class UserService implements IUserService {
	
	@Override
	public void save() {
		System.out.println("save....");
	}
	
	@Override
	public void select(Long id) {
		System.out.println("select..."+id);
	}
	
	public void cglibTest(String string){
		System.out.println(string);
	}
}

2.编写Cglib动态代理

方式一:

public class SonCglib{
	
	final UserService userService=new UserService();
	
	/**
	 *  使用Enhancer类中的create方法创建代理对象
	 *
	 *  创建代理对象要求被代理类不能是最终类
	 *
	 *  create方法的参数:
	 *      Class:字节码,用于指定被代理对象的字节码。
	 *
	 *      Callback:用于提供增强的代码,写如何代理。一般是写该接口的实现类,通常情况下是匿名内部类,但不是必须的。
	 */
	UserService userServiceCglib = (UserService) Enhancer.create(userService.getClass(), new MethodInterceptor() {
		/**
		 * 执行被代理对象的任何接口方法都会经过该方法
		 *
		 * @param proxy   代理对象的引用
		 * @param method  当前执行的方法
		 * @param args    当前执行方法所需的参数
		 * @param methodProxy :当前执行方法的代理对象
		 * @return
		 * @throws Throwable
		 */
		@Override
		public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
		
			System.out.println("-------------------------------");
			System.out.println("进入动态代理类。。。。。。。。");
			
			Object returnValue = null;
			
			//对cglibTest方法增强
			if("cglibTest".equals(method.getName())) {
				//获取参数
				String str = (String) args[0];
				//对参数做点改变
				str+="____World!";
				returnValue = method.invoke(userService, str);
			}
			return returnValue;
		}
	});
	
}

方式二:

public class SonCglib implements  MethodInterceptor {
	
	
	/**
	 * 获取代理对象
	 * @param object 被代理对象
	 * @return 代理对象
	 */
	public Object createProxy(Object object){
		//得到Enhancer类中实例
		Enhancer eh = new Enhancer();
		//设置被代理对象的类为父类
		eh.setSuperclass(object.getClass());
		//设置代理对象的回调
		eh.setCallback(this);
		//创建代理对象
		return eh.create();
	}
	
	
	@Override
	public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
		System.out.println("-------------------------------");
		System.out.println("进入动态代理类。。。。。。。。");
		
		Object returnValue = null;
		
		//对cglibTest方法增强
		if("cglibTest".equals(method.getName())) {
			//获取参数
			String str = (String) objects[0];
			//对参数做点改变
			str+="____World!";
			objects[0]=str;
			returnValue = methodProxy.invokeSuper(o,objects);
		}
		return returnValue;
	}
}

3.执行测试

方式一:

public class CglibTest {
	
	@Test
	public void  test(){
		
		SonCglib sonCglib = new SonCglib();
		//未被动态代理
		sonCglib.userService.select(1L);
		sonCglib.userService.cglibTest("Hello ");
		
		//基于子类的动态代理
		sonCglib.userServiceCglib.select(1L);
		sonCglib.userServiceCglib.cglibTest("Hello ");
	}
}

在这里插入图片描述
方式二:

public class CglibTest {
	
	@Test
	public void  test(){
		
		SonCglib cglib = new SonCglib();
		UserService userService = (UserService) cglib.createProxy(new UserService());
		userService.cglibTest("Hello ");
	}
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CodeDevMaster

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值