java设计模式--代理模式(静态,jdk,cglib)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_37415950/article/details/80978634
设计思路:

 代理(Proxy)是一种设计模式,提供了对目标对象另外的访问方式;即通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上, 增强额外的功能操作,即扩展目标对象的功能.这里使用到编程中的一个思想:不要随意去修改别人已经写好的代码或者方法,如果需改修改,可以通过代理的方式来扩展该方法

实际应用场景: aop

案列:

        通俗说法:谈恋爱,你不想去送礼物,不想干那些比较烦人并且不重要的事(当然重要的还是我们自己来是不),你就叫个人来代替你去送礼物等(或者我就压根不会送礼物,需要代理扩展)其实你就要直接和她恋爱(这里不写太直接了,你们懂就好了),这就是代理模式(注意:此方法需谨慎现实别模仿,不然就搞不好就给别人做嫁衣了,到时候别跑来骂我)


代码:

静态代理:

接口:

package com.sl.demo.proxy;
/**
 * 接口
 * @author pengkun
 *
 */
public interface Subject {
	
	/**
	 * 约会
	 */
	void engagement();
	
}

目标类:

package com.sl.demo.proxy;
/**
 * 小明同学
 * @author pengkun
 *
 */
public class XiaoMingStudent implements Subject {

	@Override
	public void engagement() {
		System.out.println("哈哈,小明同学约会去络!");
	}

}

代理:

package com.sl.demo.proxy;


/**
 * 代理类
 * @author pengkun
 *
 */
public class Proxy implements Subject{
	//需要代理的学生
	private Subject student;
	
	//创建构造函数,你总得让我知道给谁代理吧
	public Proxy(Subject student) {
		super();
		this.student = student;
	}
	//代理扩展送花
	public void sendFlower() {
		System.out.println("Proxy替小明送花");
	}
	//代理扩展送巧克力
	public void sendChocolate() {
		System.out.println("Proxy替小明送巧克力");
	}

	@Override
	public void engagement() {
		//其他杂活累活让代理去干
		this.sendFlower();
		this.sendChocolate();
		//约会肯定小明同学自己来啦
		student.engagement();
		System.out.println("搞定收工");
		
	}

}

测试:

@Test
	public void test() {
		//目标对象
		Subject xm=new XiaoMingStudent();
		//创建代理,给目标对象
		Proxy proxy=new Proxy(xm);
		proxy.engagement();
	}

结果:


可以看出,代理类扩展了送花和送巧克力的方法,而小明同学只做最爽的那下就行了。。。

静态代理在使用时,需要定义接口或者父类,被代理对象与代理对象一起实现相同的接口或者是继承相同父类.

总结:

优:可以不修改目标类的情况扩展功能,

缺:因为要实现或继承同一个接口所有代理类会很多,而且每次扩展功能的时候都要修改代理和接口

那怎么解决呢?就是下面讲的动态代理了

动态代理:也叫jdk动态代理

特点:代理对象不需要实现接口,当是目标对象必须实现

package com.sl.demo.proxy;

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

/**
 * 创建动态代理对象
 * jdk代理
 * @author pengkun
 *
 */
public class ProxyFactory {
	//持有一个目标对象
	private Object target;

	public ProxyFactory(Object target) {
		super();
		this.target = target;
	}
	//给目标对象创建代理对象
	public Object getProxyInstance() {
		//1.loader:指定当前目标对象使用类加载器,获取加载器的方法是固定的
		//2.interfaces:目标对象实现的接口的类型,使用泛型方式确认类型
		//3.h:事件处理,执行目标对象的方法时,会触发事件处理器的方法,会把当前执行目标对象的方法作为参数传入
		return Proxy.newProxyInstance(
				target.getClass().getClassLoader(), 
				target.getClass().getInterfaces(), 
				new InvocationHandler() {
					
					@Override
					public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
						System.out.println("帮小明送花");
						System.out.println("帮小明送巧克力");
						//让小明自己去约会
						Object returnValue= method.invoke(target, args);
						System.out.println("搞定收工");
						return returnValue;
					}
				}
			);
	}
	
}

测试:

@Test
public void testJDK() {
	//目标对象
	Subject xm=new XiaoMingStudent();
	//创建代理,给目标对象
	Subject proxy=(Subject) new ProxyFactory(xm).getProxyInstance();
	proxy.engagement();
}

结果:


Cglib代理:

特点:

1.引入jar包spring-core-4.2.5.RELEASE.jar(注意spring-core-3.2以上才会包含cglib,3.2以下要导入cglib.jar包)
2.代理的类不能为final,否则报错
3.目标对象方法不能为final/static,否则不会拦截即不会执行扩展功能

4.与jdk动态代理区别就是目标类不用实现接口

注意:目标对象是没实现接口的

package com.sl.demo.proxy;
/**
 * 小明同学
 * cglib目标类 不实现接口
 * @author pengkun
 *
 */
public class XiaoMingStudent2 {

	public void engagement() {
		System.out.println("哈哈,小明同学约会去络!");
	}

}

package com.sl.demo.proxy;

import java.lang.reflect.Method;

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
/**
 * Cglib代理
 * MethodInterceptor:方法拦截
 * @author pengkun
 *
 */
public class CglibProxyFactory implements MethodInterceptor {
	//持有一个 目标对象(注意:目标对象没有实现接口)
	private Object target;

	public CglibProxyFactory(Object target) {
		super();
		this.target = target;
	}
	
	//给目标对象创建个代理
	public Object getProxyInstance() {
		//创建工具类
		Enhancer en=new Enhancer();
		//设置父类
		en.setSuperclass(XiaoMingStudent2.class);
		//设置回调函数
		en.setCallback(this);
		//创建代理对象(子类)并返回
		return en.create();
	}

	/**
	 * 拦截
	 * obj:目标对象
	 * method:目标方法
	 * args:方法参数
	 * MethodProxy:它应该是cglib生成用来代替Method对象的一个对象
	 */
	@Override
	public Object intercept(Object obj, Method method, Object[] args, MethodProxy arg3) throws Throwable {
		System.out.println("帮小明送花");
		System.out.println("帮小明送巧克力");
		//让小明自己去约会
		Object returnValue= method.invoke(target, args);
		System.out.println("搞定收工");
		return returnValue;
	}

}

测试:

@Test
public void testCGLIB() {
	//目标对象
	XiaoMingStudent2 xm=new XiaoMingStudent2();
	//创建代理,给目标对象
	XiaoMingStudent2 proxy= (XiaoMingStudent2) new CglibProxyFactory(xm).getProxyInstance();
	proxy.engagement();
}


最后总结:

目标对象有实现接口就用JDK代理,

目标对象没有实现接口就用Cglib代理

猜你喜欢

转载自blog.csdn.net/qq_37415950/article/details/80978634
今日推荐