设计模式---动态代理

常用的代理模式有两种JDK动态代理(JDK自带的)和CGLIB(第三方提供的技术)

代理需要分为两个步骤:

1、建立代理对象和真实对象之间的代理关系。

2、实现代理对象中的代理逻辑方法。

一、JDK动态代理。

JDK动态代理必须借助一个接口才能产生代理对象,因此真实对象也就必须实现此接口。

一个接口

/*
 * JDK动态代理必须借助接口才能创建代理对象
 * */
public interface IPerson {
  public void say(String name);
}

接口的实现类(真实对象)

//真实对象
public class PersonImpl implements IPerson {

	@Override
	public void say(String name) {
		System.out.println("我的名字是"+name);
	}
}

定义代理逻辑类,代理逻辑类必须实现InvocationHandler接口,并实现invoke方法

public class JDKPersonProxy implements InvocationHandler{
	private Object target=null;
    /*
     * 建立代理对象和真实对象之间的代理关系并返回代理对象
     * @param 真实对象或目标对象
     * @return 代理对象
     * */
    public Object bind(Object target) {
    	this.target=target;	
    	Object proxy=Proxy.newProxyInstance(target.getClass().getClassLoader(),//目标类的加载器
    			target.getClass().getInterfaces(),//将代理对象挂在哪些接口下,也就是要增强哪些接口的功能,这也是为什么JDK动态代理要借助接口的原因
    			this);//实现InvocationHandler接口的实例
    	return proxy;
    }
    /* 实现代理逻辑方法
     * 当外界的代理对象调用相应方法时,就会回调到这里
     * @param proxy 代理对象
     * @param method 要调用的方法
     * @param args 方法的参数
     * @return 执行结果
     * */
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		System.out.println("进入代理逻辑方法");
		System.out.println("在调用真实对象方法之前的操作");
		Object obj=method.invoke(target, args);//通过反射来调用真实对象方法
		System.out.println("在调用真实对象方法后的操作!");
		return obj;
	}
}

测试类

public class Test {

	public static void main(String[] args) {
		JDKPersonProxy jdkPersonProxy=new JDKPersonProxy();
		IPerson proxy=(IPerson)jdkPersonProxy.bind(new PersonImpl());
		//此时的proxy对象是一个代理对象调用say()方法会进入代理逻辑方法invoke()中
		proxy.say("小明");
	}
}

打印结果

进入代理逻辑方法
在调用真实对象方法之前的操作
我的名字是小明
在调用真实对象方法后的操作!

二、CGLIB动态代理

如果我们的真实对象没有实现任何接口,但是我们还想给他设置一个代理对象怎么办呢,显然通过JDK动态代理是不行的,这里我们采用CGLIB动态代理的方式。注意:因为CGLIB是第三方提供的技术因此需要下载jar包并添加到项目中。

一个未实现任何接口的类

//未实现接口的真实对象
public class Person {
     public void play(String name) {
    	 System.out.println(name+"正在打篮球!");
     }
}

代理逻辑类

public class CGLIBPersonProxy implements MethodInterceptor{
	/*
	 * 获取代理对象
	 * @param c Class类
	 * @return Class类的代理对象
	 * */
	public Object getProxy(Class c) {
		Enhancer enhancer=new Enhancer();//增强类对象
		/*
		 * 设置增强类型
		 * */
		enhancer.setSuperclass(c);
		//定义代理逻辑对象为当前对象,当前对象要实现MethodInterceptor接口,并实现其中的代理逻辑方法
		enhancer.setCallback(this);
	    /*
	     * 生成并返回代理对象。本质上其实是创建并返回了c的子类,通过子类来增强父类的功能。
	     * */
		return enhancer.create();
	}
	//返回的代理类调用相应方法会回调这里
	@Override
	public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
		System.out.println("已经进入逻辑代理方法");
		System.out.println("调用真实对象方法前");
		//CGLIB反射调用真实方法
		Object res=methodProxy.invokeSuper(proxy, args);
		System.out.println("调用真实对象方法后");
		return res;
	}
}
测试类
public class Test {

	public static void main(String[] args) {
		CGLIBPersonProxy cglibPersonProxy=new CGLIBPersonProxy();
		Person proxy=(Person) cglibPersonProxy.getProxy(Person.class);
		proxy.play("小张");
	}
}

打印结果

已经进入逻辑代理方法
调用真实对象方法前
小张正在打篮球!
调用真实对象方法后

猜你喜欢

转载自blog.csdn.net/start_mao/article/details/79540707