一、核心作用

间接对目标对象进行访问

可以详细控制某个对象的方法,对目标对象的实现功能上,增加额外的功能补充,扩展目标对象功能

二、常见应用场景

1、安全代理:屏蔽对真实角色的直接访问

2、远程代理:通过代理类处理远程方法的调用

3、延时加载:先加载轻量级,真正需要再加载真实对象

三、代理角色分类


  • 抽象角色:定义代理角色和真实角色的公共对外方法
  • 真实角色:实现抽象角色,定义真实角色要实现的业务逻辑,供代理角色调用
  • 代理角色:实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑来实现抽象方法,并附加自己的操作
    GOF23之代理模式_aop

四、代理模式分类:

1、静态代理

2、动态代理

3、Cglib代理

五、代码示例:

一、静态代理:

抽象角色:
package com.hezeu.proxy.staticProxy;

/**
* @Classname Star
* @Description 抽象角色
* @Date 2020/2/22 下午 06:41
* @Created by 朱进博 1724282894@qq.com
*/
public interface Star {
void confer();

void signContract();

void bookTicket();

void sing();

void collectMoney();
}
真实角色:
package com.hezeu.proxy.staticProxy;

/**
* @Classname RealStar
* @Description TODO
* @Date 2020/2/22 下午 06:46
* @Created by 朱进博 1724282894@qq.com
*/
public class RealStar implements Star {
@Override
public void confer() {
System.out.println("RealStar.confer");
}

@Override
public void signContract() {
System.out.println("RealStar.signContract");
}

@Override
public void bookTicket() {
System.out.println("RealStar.bookTicket");
}

@Override
public void sing() {
System.out.println("RealSta(周杰伦本人).sing");
}

@Override
public void collectMoney() {
System.out.println("RealStar.collectMoney");
}
}
代理角色:
package com.hezeu.proxy.staticProxy;

/**
* @Classname ProxyStar
* @Description TODO
* @Date 2020/2/22 下午 06:48
* @Created by 朱进博 1724282894@qq.com
*/
public class ProxyStar implements Star{

private Star star;

public ProxyStar(Star star) {
this.star = star;
}

@Override
public void confer() {
System.out.println("ProxyStar.confer");
}

@Override
public void signContract() {
System.out.println("ProxyStar.signContract");
}

@Override
public void bookTicket() {
System.out.println("ProxyStar.bookTicket");
}

@Override
public void sing() {
star.sing();
}

@Override
public void collectMoney() {
System.out.println("ProxyStar.collectMoney");
}
}
测试:
package com.hezeu.proxy.staticProxy;

/**
* @Classname Client
* @Description 测试
* @Date 2020/2/22 下午 07:58
* @Created by 朱进博 1724282894@qq.com
*/
public class Client {
public static void main(String[] args) {
Star real = new RealStar();
Star proxy = new ProxyStar(real);
proxy.confer();
proxy.signContract();
proxy.bookTicket();
proxy.sing();
proxy.collectMoney();
}
}

测试结果如下:

GOF23之代理模式_java_02

静态代理的优缺点:

优点:可以做到不修改目标对象功能的前提下对功能进行扩展或修改,符合开闭原则

缺点:因为代理对象需要与目标对象实现相同的接口,代理类爱多,同时一旦抽象角色增加方法,真实角色和代理角色都要维护,工作量大,不宜管理

二、动态代理:

使用JDK自带的动态代理
java.lang.reflect.Proxy 动态生成代理类和对象
java.lang.reflect.InvocationHandler(处理器接口)
可以通过invoke方法实现对真实角色的代理访问
每次通过proxy生成的代理类对象都要指定对应的处理器对象

package com.hezeu.proxy.dynamicProxy;

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

/**
* @Classname StarHandler
* @Description TODO
* @Date 2020/2/22 下午 08:16
* @Created by 朱进博 1724282894@qq.com
*/
public class StarHandler implements InvocationHandler {
Star realStar;

public StarHandler(Star realStar) {
this.realStar = realStar;
}

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object obj = null;
System.out.println("真正的方法执行前!");
System.out.println("面谈,签合同,预付款,订机票");

if(method.getName().equals("sing")){
obj = method.invoke(realStar, args);
}

System.out.println("真正的方法执行后!");
System.out.println("收尾款");
return obj;
}
动态代理相较于静态代理的优缺点:
对于静态代理而言,动态代理建好了开发的任务,减少了对业务接口的依赖,降低了耦合度

三、Cglib代理:


第三方代理技术,可以对目标对象接口实现代理,也可以进行继承代理,底层是动态的在内存中生成了目标对象的子类的字节码,并生成了相应的对象。
CGlib实现动态代理能满足没有接口的目标对象的代理对象实现。JDK动态代理与CGlib动态代理是实现Spring AOP的基础


代码示例:
真实角色(没有实现接口)
package com.hezeu.proxy.CGlib;

/**
* @Classname RealStar
* @Description TODO
* @Date 2020/2/22 下午 06:46
* @Created by 朱进博 1724282894@qq.com
*/
public class RealStar {

public void confer() {
System.out.println("RealStar.confer");
}

public void signContract() {
System.out.println("RealStar.signContract");
}

public void bookTicket() {
System.out.println("RealStar.bookTicket");
}

public void collectMoney() {
System.out.println("RealStar.collectMoney");
}

public void sing() {
System.out.println("RealStar(CGlib周杰伦).sing");
}
}
cglib代理类,需要实现MethodInterceptor
package com.hezeu.proxy.CGlib;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;
/**
* @Classname ProxyStar
* @Description TODO
* @Date 2020/2/22 下午 10:09
* @Created by 朱进博 1724282894@qq.com
*/
public class ProxyStar implements MethodInterceptor {
private Object target;

public Object getInstance(Object target){
this.target=target;
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(this.target.getClass());
enhancer.setCallback(this);
return enhancer.create();
}

@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("事物开始");
Object result = methodProxy.invokeSuper(o,objects);
System.out.println("事物结束");
return result;
}
}
测试类:
package com.hezeu.proxy.CGlib;

/**
* @Classname Client
* @Description TODO
* @Date 2020/2/22 下午 08:20
* @Created by 朱进博 1724282894@qq.com
*/
public class Client {
public static void main(String[] args) {
ProxyStar proxy = new ProxyStar();
RealStar realStar = (RealStar) proxy.getInstance(new RealStar());
realStar.sing();


}
}

动态代理和CGlib代理总结

使用JDK动态代理需要实现一个或多个接口,若想代理没有实现接口的类,需要使用Cglib
使用Cglib 需要导入
cglib-xxx.jar
asm-xxx.jar

在Spring的AOP编程中
如果加入容器的目标对象有实现接口用JDK代理
如果目标对象没有实现接口,用Cglib代理