代理设计模式(普通静态代理、JDK动态代理、cglib动态代理)

1、普通静态代理:


代理设计模式:

代理设计模式中,一个类代表另外一个类的功能,这种类型的设计模式属于结构性设计模式。

    对于被代理人来讲,这件事情是一定要去做的,但是我自己又不想做或者没有时间做,则需要找代理。

    当我们想要对一个类的访问做出一些个控制,这个时候我们就要使用代理设计模式。


代理设计模式的使用场景:

西游记的案例:

猪八戒要去高老庄找高翠兰小姐,但是找到的确是孙悟空变化成的高翠兰。

这个场景可以这样理解:

先把高翠兰的外貌特征抽取出来变成一个接口,然后高翠兰本人和孙悟空两个类都去实现这个外貌的接口,当猪八戒去访问的时候,猪八戒其实访问的是

孙悟空,但是由于外貌是高翠兰的,所以他看不出来是孙悟空。在这里,高翠兰本人是被代理类,孙悟空是代理类

火车站售票点的案例:

火车站售票点帮助火车站出售火车票,场景也可以自行推倒。


下面是整个代码的案例结构(其中Image接口表示高翠兰的长相,RealImage是高翠兰本人,ProxyImage是孙悟空这个代理):

代理设计模式(普通静态代理、JDK动态代理、cglib动态代理)_第1张图片


下面代码是西游记案例的实现代码:

Image,java

package com.zwz.test;

public interface Image {

	
	public void display();
	
	
}


ProxyImage.java

package com.zwz.test;


public class ProxyImage implements Image{

	private String filename;

	private RealImage realImage;
	
	
	public String getFilename() {
		return filename;
	}

	public void setFilename(String filename) {
		this.filename = filename;
	}

	public ProxyImage(String filename) {
		super();
		this.filename = filename;
	}

	@Override
	public void display() {
		// TODO Auto-generated method stub
		//System.out.println(filename+"   display");
		if(realImage==null){
			realImage = new RealImage( filename);
		}
		realImage.display();
	
	}
	
}



RealImage.java

package com.zwz.test;

public class RealImage implements Image{

	private String filename;

	
	
	public String getFilename() {
		return filename;
	}



	public void setFilename(String filename) {
		this.filename = filename;
	}



	public RealImage(String filename) {
		super();
		this.filename = filename;
		loadFromDisk();
	}



	private void loadFromDisk() {
		// TODO Auto-generated method stub
		System.out.println(filename+"    is loading");
	}



	@Override
	public void display( ) {
		// TODO Auto-generated method stub

		System.out.println(filename+"   display");
		
	}
	
	
	
	
}


ProxyPatternDemo.java

package com.zwz.test;

public class ProxyPatternDemo {

	public static void main(String[] args) {
		
		Image image = new ProxyImage("gaocuilan");
		
		image.display();
		
	}
	
}


最后的输出结果如下图所示:

代理设计模式(普通静态代理、JDK动态代理、cglib动态代理)_第2张图片





上面的篇幅以及代码主要介绍的 java中的静态代理,下面的代码则是介绍 动态代理,动态代理在springAOP的代码中应用较为广泛,

在面向切面(AOP)编程当中,动态代理可以理解为,想要实现一种功能,我们不让其本类去直接实现,而是去

获取到其代理类,让代理类在实现功能的前后干点坏事,spring当中 AOP的具体体现就是 前置通知、后置通知、环绕通知、异常通知这些。


2.JDK动态代理

   在实现 JDK 动态代理之前,需要新建一个接口文件,让某个需要被代理的类去实现这个接口,然后待会儿jdk创建出来的代理对象也实现  InvocationHandler 这个接口,用来代理被代理的对象,完成其方法,并且可以在其方法前后增加代码.

具体实现如下:

首先先建一个接口文件:

Hello.java

public interface Hello {

	public void sayHello();
	
}

然后新建一个实现这个接口的Class类

HelloImpl.java

public class HelloImpl implements Hello{

	public void sayHello() {
		// TODO Auto-generated method stub
		System.out.println("HelloImpl say hello!!");
	}

}

实现JDK动态代理的类(需要实现 InvocationHandler接口):

JDKProxy.java

public class JDKProxy implements InvocationHandler{

	//这个obj是要被jdk动态代理的对象
	private Object obj;

	//传入要被代理的对象
	public JDKProxy(Object obj) {
		super();
		this.obj = obj;
	}

	public void before(){
		System.out.println("say before!!");
	}
	
	public void after(){
		System.out.println("say after!!");
	}
	
	//invoke方法 是   代理对象执行 被代理对象的方法
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		// TODO Auto-generated method stub
		//代理方法之前干点坏事
		before();
		
		Object result = method.invoke(obj, args);
		//代理方法之后干点坏事
		after();
		
		return result;
	
	}

	/*
	 Proxy.newProxyInstance这个方法的三个传入参数和含义如下:
	 参数1:传入一个   当前类的加载器
	 参数2:传入一个  当前类的接口文件
	 参数3:实现了  InvokeHandler的子类对象  
	 */
	public T getProxy( ){
		return (T)Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), this);
	}
	
	public static void main(String[] args) {
		
		HelloImpl hi = new HelloImpl();
		JDKProxy proxy = new JDKProxy(hi);
		
		Hello hii = proxy.getProxy();
		hii.sayHello();
		
	}
	
	
}


运行main函数输出结果:

代理设计模式(普通静态代理、JDK动态代理、cglib动态代理)_第3张图片


3.CGLIB 动态代理

cglib的动态代理和jdk的动态代理最大的区别在于,cglib当中被代理的对象不需要实现接口,cglib直接代理其对象。

CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法(继承)

实现代码如下  CGlibProxy.java:

public class CGlibProxy implements MethodInterceptor{

	public void before(){
		System.out.println("before method");
	}
	
	public void after(){
		System.out.println("after method");
	}
	
	public T getProxy(Classcls){
		return (T)Enhancer.create(cls, this);
	}
	
	public Object intercept(Object obj, Method method, Object[] args,
			MethodProxy methodProxy) throws Throwable {
		// TODO Auto-generated method stub
		
		before();
		
		Object result = methodProxy.invokeSuper(obj, args);
		
		after();
		return result;
	}

	public static void main(String[] args) {
		
		CGlibProxy proxy = new CGlibProxy();
		
		HelloImpl hi = proxy.getProxy(HelloImpl.class);
	
		hi.sayHello();
	
	}
}

运行代码,得到输出:

代理设计模式(普通静态代理、JDK动态代理、cglib动态代理)_第4张图片





在spring的代码当中jdk的动态代理和cglib的动态代理都会使用到

在spring的  DefaultAopProxyFactory.java  文件中 createAopProxy  方法代码如下:

@Override
	public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
		if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
			Class targetClass = config.getTargetClass();
			if (targetClass == null) {
				throw new AopConfigException("TargetSource cannot determine target class: " +
						"Either an interface or a target is required for proxy creation.");
			}
			if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
				return new JdkDynamicAopProxy(config);
			}
			return new ObjenesisCglibAopProxy(config);
		}
		else {
			return new JdkDynamicAopProxy(config);
		}
	}

可以看到在spring源码中判断当前的类是否有实现接口,如果没有实现则使用cglib的动态代理,如果实现了,则使用jdk的动态代理。



你可能感兴趣的:(设计模式)