Java代理模式 核心思想 :我不行就找别人 不勉强自己
Java中典型的代理模式:SpringAOP HIbernate数据查询
代理模式分类:静态代理和动态代理
静态代理:
聚合方式:将目标类作为代理类的成员变量 使用构造器将目标类注入 要求代理类和目标类实现相同接口
//公共接口
package com.briup.Proxy.Static;
public interface car {
public void drive();
}
//目标类(被代理了)
package com.briup.Proxy.Static;
public class OrdinaryCar implements car {
@Override
public void drive() {
System.out.println("开车");
}
}
//代理类
package com.briup.Proxy.Static;
public class ProxyCar implements car {
//引用目标对象
private car c;
public ProxyCar(car c) {
this.c = c;
}
@Override
public void drive() {
//目标对象的操作
c.drive();
//对代理类额外做的操作(对目标类功能的扩展)
System.out.println("边开车边唱歌");
}
}
//测试类代码
public class Test {
public static void main(String[] args) {
car ordinaryCar = new OrdinaryCar();
car proxyCar = new ProxyCar(ordinaryCar);
proxyCar.drive();
}
}
继承方式: 通过子类继承父类的方式进行功能的扩展(不建议使用)
//子类实现
package com.briup.Proxy.Static;
public class ProxyCar_2 extends OrdinaryCar {
@Override
public void drive() {
System.out.println("开车前不喝酒");
super.drive();
System.out.println("边开车边喝酒");
}
}
//测试类
package com.briup.Proxy.Static;
public class Test {
public static void main(String[] args) {
ProxyCar_2 proxyCar_2 = new ProxyCar_2();
proxyCar_2.drive();
}
}
动态代理
jdk动态代理:代理类和目标类需要实现同一接口(是SpringAOP的优先选择)使用JDK提供的类实现代理模式主要的类有Proxy InvoktionHandler
//接口:
package com.briup.Proxy.dynamic.JDK;
public interface Update {
public void one();
public void two();
}
//目标类
package com.briup.Proxy.dynamic.JDK;
public class UpdateImp implements Update{
@Override
public void one() {
System.out.println("one");
}
@Override
public void two() {
System.out.println("two");
}
}
//JDK动态代理类
package com.briup.Proxy.dynamic.JDK;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class ProxyJDK implements InvocationHandler {
private Object target;
public ProxyJDK(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] objects) throws Throwable {
System.out.println("开车之前先考驾照");
Object invoke = method.invoke(target, objects);
System.out.println("开车之后喝点小酒");
return invoke;
}
}
//测试类
public class Test {
public static void main(String[] args) {
car ordinaryCar = new OrdinaryCar();
car car= (com.briup.Proxy.Static.car) Proxy.newProxyInstance(Test.class.getClassLoader(),
new Class[]{car.class}, new ProxyJDK(ordinaryCar));
car.drive();
UpdateImp updateImp = new UpdateImp();
Update up= (Update) Proxy.newProxyInstance(Test.class.getClassLoader(),
new Class[]{Update.class},new ProxyJDK(updateImp));
up.one();
up.two();
}
}
Cglib动态代理 :代理类和目标类不需要实现相同接口
Cglib代理是功能最为强大的一种代理方式,因为其不仅解决了静态代理需要创建多个代理类的问题,还解决了jdk代理需要被代理对象实现某个接口的问题。对于需要代理的类,如果能为其创建一个子类,并且在子类中编写相关的代理逻辑,因为“子类 instanceof 父类”,因而在进行调用时直接调用子类对象的实例,也可以达到代理的效果。Cglib代理的原理实际上是动态生成被代理类的子类字节码,由于其字节码都是按照jvm编译后的class文件的规范编写的,因而其可以被jvm正常加载并运行。这也就是Cglib代理为什么不需要为每个被代理类编写代理逻辑的原因。这里需要注意的是,根据Cglib实现原理,由于其是通过创建子类字节码的形式来实现代理的,如果被代理类的方法被声明final类型,那么Cglib代理是无法正常工作的,因为final类型方法不能被重写
依赖导入:
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.2.2</version>
</dependency>
代码实现:
//目标类沿用JDK代理的例子
//Cglib代理类
package com.briup.Proxy.dynamic.Cglib;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class CglibProxy implements MethodInterceptor {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("代理之前");
Object o1 = methodProxy.invokeSuper(o, objects);
System.out.println("代理之后");
return o1;
}
}
//测试类
package com.briup.Proxy.dynamic.Cglib;
import com.briup.Proxy.dynamic.JDK.UpdateImp;
import net.sf.cglib.proxy.Enhancer;
public class Test {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(UpdateImp.class);
enhancer.setCallback(new CglibProxy());
UpdateImp up= (UpdateImp) enhancer.create();
up.one();
}
}
代理模式的优缺点:
优点:
- 可以在保证开闭原则的前提下 对目标进行功能扩展
- 协调了调用者和被调用者 降低了耦合性
- 在客户端和目标对象间添加代理对象 起到了保护目标对象的作用
缺点:
- 在调用目标对象方法前 先调用代理类的方法 提高了代码非复杂性 增加程序运行时间