当前位置: 代码迷 >> 综合 >> java设计模式--代理模式(静态,jdk,cglib)
  详细解决方案

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

热度:103   发布时间:2023-11-13 16:21:02.0
设计思路:

 代理(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 {@Overridepublic 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替小明送巧克力");}@Overridepublic void engagement() {//其他杂活累活让代理去干this.sendFlower();this.sendChocolate();//约会肯定小明同学自己来啦student.engagement();System.out.println("搞定收工");}}

测试:

@Testpublic 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() {@Overridepublic 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对象的一个对象*/@Overridepublic 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代理

  相关解决方案