代理模式(Proxy Pattern)

代理模式

说明

代理模式(Proxy Pattern)属于结构性模式,是指为其他对象提供一种代理,以控制对这个对象的访问。
在不修改目标对象的情况下对目标对象进行增强,Spring的AOP本质就是代理模式。

静态代理

定义一个接口

package com.gupaoedu.service;

public interface SomeService {
	public String doSome(String msg);
}

定义目标对象,实现接口中的方法

/**
* 
* 代理模式的目标对象
*/
public class SomeServiceImpl implements SomeService {
	public String doSome(String msg) {
		System.out.println("目标对象方法执行了...." + msg);
		return "hello";
	}
}

定义静态代理类,实现接口中的方法,并且包含对目标对象的引用,在方法中调用目标对象的方法,同时在调用方法前后可以根据需要进行增强

public class StaticSomeProxy implements SomeService {
	private SomeService target; // 需要增强的目标对象
	public StaticSomeProxy(SomeService target) {
		this.target = target;
	}
	
	public String doSome(String msg) {
		System.out.println("目标对象执行之前的操作....");
		// 调用目标对象的方法
		String res = target.doSome(msg);
		System.out.println("目标对象执行之后的操作....");
		return res.toUpperCase();
	}
}

测试

public static void main(String[] args) {
	// 获取目标对象
	SomeService target = new SomeServiceImpl();
	// 获取代理对象 增强目标对象
	SomeService proxy = new StaticSomeProxy(target);
	// 处理
	System.out.println(proxy.doSome("nihao"));
}

动态代理

JDK动态代理

如果目标对象有实现接口,可以使用JDK动态代理

public class Test02 {
	public static void main(String[] args) {
		// 获取目标对象
		final SomeService target = new SomeServiceImpl();
		// 获取代理对象
		SomeService proxy = (SomeService) Proxy.newProxyInstance(
			target.getClass().getClassLoader() // 类加载器
			, target.getClass().getInterfaces() // 目标对象实现的接口数组
			, new InvocationHandler() { // InvocationHandler的实现
				/**
				* 当代理对象执行相关方法的时候会执行的逻辑
				* @return
				* @throws Throwable
				*/
				public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
					System.out.println("目标方法执行之前....");
					// 调用目标对象的方法
					String msg = (String) method.invoke(target, args[0]);
					System.out.println("目标方法执行之后....");
					return msg.toUpperCase();
				}
			});
			
		System.out.println(proxy.doSome("aaa"));
	}
}

CGLIB动态代理

如果目标对象没有实现任何的接口那么我们是使用不了JDK动态代理的,那么这个时候我们只能使用
CGLIB代理。CGLIB的本质其实的代理类继承了目标对象,并重写相关方法。

引入依赖

<dependencies>
	<dependency>
		<groupId>cglib</groupId>
		<artifactId>cglib</artifactId>
		<version>2.2.2</version>
	</dependency>
</dependencies>

创建目标对象

public class SomeServiceImpl implements SomeService {
	public String doSome(String msg) {
		System.out.println("目标对象方法执行了...." + msg);
		return "hello";
	}
}

创建代理类

public class CglibProxy implements MethodInterceptor {
	private UserServiceImpl target;
	public CglibProxy(UserServiceImpl target) {
		this.target = target;
	}
	
	/**
	* 给外界暴露的创建代理对象的方法
	* @return
	*/
	public UserServiceImpl createProxy(){
		Enhancer enhancer = new Enhancer();
		// 指定父类
		enhancer.setSuperclass(UserServiceImpl.class);
		// 指定回调方法
		enhancer.setCallback(this);
		// 创建对象代理对象
		return (UserServiceImpl) enhancer.create();
	}
	
	/**
	* 需要执行具体的代理方法
	* @param o
	* @param method
	* @param objects
	* @param methodProxy
	* @return
	* @throws Throwable
	*/
	public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
		System.out.println("before...");
		String msg = (String) method.invoke(target, objects[0]);
		System.out.println("after...");
		return msg.toUpperCase();
	}
}

测试

public class Test03 {
	public static void main(String[] args) {
		// 获取目标对象
		UserServiceImpl target = new UserServiceImpl();
		// 获取代理对象
		UserServiceImpl proxy = new CglibProxy(target).createProxy();
		System.out.println(proxy.say("gp"));
	}
}

JDK与Cglib的区别

  1. JDK动态代理实现了被代理对象的接口,CGLib代理继承了被代理对象;
  2. JDK动态代理和CGLib代理都是在运行期间生成字节码,JDK动态代理直接写Class字节码,CGLib代理使用ASM框架写Class字节码,CGLib代理实现更加复杂,生成代理类比JDK动态代理效率低;
  3. JDK动态代理调用代理方法是通过反射机制调用的,CGLib代理是通过FastClass机制直接调用的,CGLib代理的执行效率更高;
  4. Cglib不能代理final的方法。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值