java代理模式的三种实现方式

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_34083066/article/details/87073173

代理模式含义

即通过一个代理对象来扩展目标对象,实现在不改变目标对象的基础上,为目标对象添加新的功能。同时,还防止了修改原有代码造成的不必要的bug。

 

假如我们现在有一个接口(MyInterface)

public interface MyInterface {

	void doSomeThing();
	
	void saySomeThing();
	
	String eatSomeThing();
	
	String buy(String something);
	
}

和他的一个实现类(MyInterfaceImpl)

public class MyInterfaceImpl implements MyInterface {

	@Override
	public void doSomeThing() {
		System.out.println("做了XXXXXX事");
	}

	@Override
	public void saySomeThing() {
		System.out.println("说了========话");
	}

	@Override
	public String eatSomeThing() {
		return "吃了好多东西";
	}

	@Override
	public String buy(String something) {
		return "买了"+something;
	}

}

静态代理

我们先做一个静态代理实现,所谓静态代理就是使代理实现要代理的接口,并在内部定义一个私有的接口变量,使必须要实现的方法,再添加了代理逻辑之后,继续调用接口的真实实现的一种方式。说起来可能表达不清。直接看代码吧。

静态代理类(Proxy)

注意这个的Proxy类不是JDK提供的,是我自己写的只不过命名相同。下面会说到JDK自带的Proxy类进行动态代理。

import com.wm.demo.proxy.interfaces.MyInterface;

/**
 * 静态代理
 * 代理优点:再不更改原方法的情况下,对功能进行扩展。
 * 静态代理缺点:随着接口功能的增加,代理类也需要维护。
 * @ClassName: com.wm.demo.proxy.staticproxy.Proxy
 * @author: wm
 * @date: 2019年2月12日 上午9:09:48
 * @version : 1.0
 */
public class Proxy implements MyInterface {

	private MyInterface myInterface;
	
	private Proxy(MyInterface myInterface) {
		this.myInterface = myInterface;
	}

	public static Proxy instance(MyInterface myInterface) {
		return new Proxy(myInterface);
	}
	
	@Override
	public void doSomeThing() {
		System.out.println("====proxy代理doSomeThing前");
		myInterface.doSomeThing();
	}

	@Override
	public void saySomeThing() {
		System.out.println("proxy代理saySomeThing前====");
		myInterface.doSomeThing();
	}

	@Override
	public String eatSomeThing() {
		System.out.println("proxy代理:吃饭前洗手");
		return myInterface.eatSomeThing();
	}

	@Override
	public String buy(String something) {
		System.out.println("proxy代理:先挣钱");
		return myInterface.buy(something);
	}

}

我们让Proxy类实现了我们上面的MyInterface接口,并且实现了他的4个方法。再Proxy中又定义了一个私有的MyInterface变量,并且通过构造器注入。

然后实现的4个方法就是我们代理模式实现代理功能的地方。

然后我们编写一个测试类:

import com.wm.demo.proxy.interfaces.MyInterface;
import com.wm.demo.proxy.interfaces.impl.MyInterfaceImpl;

public class TestStaticProxy {

	public static void main(String[] args) {
		MyInterface mi = Proxy.instance(new MyInterfaceImpl());
		mi.doSomeThing();
		mi.saySomeThing();
		String eatSomeThing = mi.eatSomeThing();
		System.out.println(eatSomeThing);
		String buy = mi.buy("球鞋");
		System.out.println(buy);
	}
}

测试结果:

====proxy代理doSomeThing前
做了XXXXXX事
proxy代理saySomeThing前====
做了XXXXXX事
proxy代理:吃饭前洗手
吃了好多东西
proxy代理:先挣钱
买了球鞋

这样一来就一目了然了。通过proxy实现了对myinterface的功能扩展还没有动到他实现中的代码。符合我们的设计模式。但是有一个问题就是静态代理因为要实现被代理的接口,所以如果该接口增加了新的功能。整个静态代理都要跟着变更。这不是我们希望的。其实JDK已经帮我们想好了。

JDK动态代理

我们的接口和接口实现还是上面的类保持不变。

我们下面写一个JDK的动态代理工厂。

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

/**
 * 动态代理工厂
 * @ClassName: com.wm.demo.proxy.dynamicproxy.ProxyFactory
 * @author: wm
 * @date: 2019年2月12日 上午9:16:02
 * @version : 1.0
 */
public class ProxyFactory<T> {

	private T target;
	
	public ProxyFactory(T target) {
		this.target = target;
	}
	
	public Object getProxyInstance() {
		return Proxy.newProxyInstance(target.getClass().getClassLoader(),
				target.getClass().getInterfaces(), (Object proxy, Method method, Object[] args)->{
					System.out.println("==========JDK动态代理==========前");
					Object invoke = method.invoke(target, args);
					System.out.println("==========JDK动态代理==========后");
					return invoke;
				});
	}
	
}

我们给类一个成员变量,并且使用了泛型注入,进行类型校验。

然后我们写一个方法,方法内调用JDK的动态代理类Proxy,我们看一下这个类

他一共只暴露了4个方法:

从名字上来看,只有newProxyInstance是构建代理的。

看一下这个方法的参数列表

    public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)

第一个是要代理的对象的类加载器。

第二个是要代理的对象的接口类型数组。

第三个是调用程序,就是说我们的代理功能在这实现。

再看一下InvocationHandler接口,内部,只有一个抽象方法等待实现:

public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable;

我们可以使用lambda进行书写。

调用method的invoke方法,使用它的类加载器,并传入的他参数列表,执行该方法。并返回值。

然后我们写一个测试类:

import com.wm.demo.proxy.interfaces.MyInterface;
import com.wm.demo.proxy.interfaces.impl.MyInterfaceImpl;

public class TestProxyFactory {

	public static void main(String[] args) {
		ProxyFactory<MyInterface> pf = new ProxyFactory<MyInterface>(new MyInterfaceImpl());
		MyInterface proxyInstance = (MyInterface)pf.getProxyInstance();
		proxyInstance.doSomeThing();
		proxyInstance.saySomeThing();
		String eatSomeThing = proxyInstance.eatSomeThing();
		System.out.println(eatSomeThing);
		String buy = proxyInstance.buy("电脑");
		System.out.println(buy);
	}
}

输入结果:

==========JDK动态代理==========前
做了XXXXXX事
==========JDK动态代理==========后
==========JDK动态代理==========前
说了========话
==========JDK动态代理==========后
==========JDK动态代理==========前
==========JDK动态代理==========后
吃了好多东西
==========JDK动态代理==========前
==========JDK动态代理==========后
买了电脑

这样我们就实现了JDK的动态代理。没有实现接口,当接口出现变更时我们的代理工厂也无需变更。

但总有一些情况,我们要代理的目标并没有实现任何接口。那么该如何进行代理呢

CGLIB代理

当我们的目标没有实现任何接口的时候,我们无法使用JDK动态代理,那么可以使用cglib进行代理。

public class MyClass {

	public void doSomeThing(String msg) {
		System.out.println("myclass做了"+msg);
	}
}
import java.lang.reflect.Method;

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

public class CglibProxyFactory<T> implements MethodInterceptor {

	private T target;
	
	private CglibProxyFactory(T target){
		this.target = target;
	}
	
	public static <T> CglibProxyFactory<T> instance(T target){
		return new CglibProxyFactory<>(target);
	}
	
	//给目标对象创建一个代理对象
    @SuppressWarnings("unchecked")
	public T getProxy(){
        //1.工具类
        Enhancer en = new Enhancer();
        //2.设置父类
        en.setSuperclass(target.getClass());
        //3.设置回调函数
        en.setCallback(this);
        //4.创建子类(代理对象)
        return (T) en.create();
    }
	
	@Override
	public Object intercept(Object obj, Method method, Object[] args, MethodProxy mp) throws Throwable {
		System.out.println("==========cglib代理前");
		Object invoke = method.invoke(target, args);
		System.out.println("cglib代理后==========");
		return invoke;
	}

}

测试类

public class TestCglib {

	public static void main(String[] args) {
		MyClass m = CglibProxyFactory.instance(new MyClass()).getProxy();
		m.doSomeThing("打篮球");
	}
}
==========cglib代理前
myclass做了打篮球
cglib代理后==========

猜你喜欢

转载自blog.csdn.net/qq_34083066/article/details/87073173
今日推荐