代理模式啦
代理模式
一.介绍
是一种常见的设计模式,属于结构型模式.
它的核心思想是通过一个 代理对象 来控制对真实对象的访问
从而在不修改目标对象的前提下,实现功能的增强
1.使用场景
权限控制
日志记录
性能检测
缓存的处理
2.分类
静态代理
在编译阶段
在写代码期间
在程序运行之前,就已经确定了代理类和被代理的类的关系
动态代理
在写代码期间,不确定被代理的类是谁
只知道写代理类和他的业务逻辑
在运行的时候,动态的创建代理类,灵活性比较高

二.静态代理
在编码阶段,已经明确知道哪个类是真实类,哪个类是代理类,二者的关系是硬编码的.
1.案例:程序员接项目
1.1 定义接口:Programmer
//程序员
public interface Programmer {
void code(Integer money);
}1.2 真实类
public class XiaoMing implements Programmer{@Overridepublic void code(Integer money) {if (money < 7000){System.out.println("拒绝上班");return;}System.out.println("获得工资:"+money);System.out.println("开开心心写代码");}
}1.3 代理类: OD公司作为代理类,承接业务
//代理类,对外说自己是程序员,其实不会写代码,需要一个真实的程序员来给他写代码
public class OD implements Programmer{
private final Programmer programmer;
public OD(Programmer programmer){this.programmer = programmer;}
@Overridepublic void code(Integer money) {System.out.println("收到甲方的工资:"+money);Integer payMoney = 10000;//保险Double xian = payMoney * 0.12;Double jin = payMoney * 0.12;//公司付出System.out.printf("公司付出:缴纳五险一金,保险%s元,公积金%s元\n",xian,jin);System.out.printf("实际发的工资:%s\n",payMoney);programmer.code(payMoney);System.out.println("公司赚了:"+(money - xian - jin - payMoney));}
}1.4 测试类
public class Hua {public static void main(String[] args) {//需要一个野生的程序员,小明Programmer xiaoming = new XiaoMing();//招聘小明,开发Programmer od = new OD(xiaoming);//支付工资od.code(40000);}
}1.5 特点
优点
逻辑清晰
易于理解和实现
缺点
每个真实类,都需要一个对应的代理类
非常不利于维护和扩展
不适合大规模的使用
三.动态代理
动态代理是在程序运行期间动态的生成代理类,具有更高的灵活性和通用性
常见的实现方式有两种:
| 类型 | 实现机制 | 依赖环境 |
|---|---|---|
| JDK动态代理 | 基于接口实现 | 必须有接口 |
| CGLib动态代理 | 基于继承实现 | 可以没有接口,需要引入cglib库 |
1.JDK动态代理
案例:方法执行的时候,统计运行时机,和性能
1.1 自定义: InvocationHandler
public class JDKInvocationHandler implements InvocationHandler {//真实类private Object target;
public JDKInvocationHandler(Object object){this.target = object;}
//Method 是被执行方法的 方法对象//args 被执行方法的参数@Overridepublic Object invoke(Object proxy,Method method,Object[] args) throws Throwable {//这个方法是用来写业务的---统计性能//进入方法的时候,记录时间long start = System.currentTimeMillis();// result 是方法执行之后的返回值Object result = method.invoke(target,args);//执行之后的时间long time = System.currentTimeMillis() - start;System.out.printf("[性能统计]方法%s,耗时%s ms \n",method.getName(),time);return result;}
}这里只写了业务逻辑,此时,还不知道被统计性能的类是谁
刚刚的代理类,会在运行时,动态生成
1.2 使用示例
public class TestJdk {public static void main(String[] args) {f2();}
private static void f2() {//真实类WebUserServiceImpl webUserServiceImpl = new WebUserServiceImpl();JDKInvocationHandler jdkInvocationHandler =new JDKInvocationHandler(webUserServiceImpl);WebUserService webUserService =(WebUserService) Proxy.newProxyInstance(WebUserServiceImpl.class.getClassLoader(),new Class[]{WebUserService.class},jdkInvocationHandler);webUserService.findById(100);}
private static void f1() {XiaoMing xiaoMing = new XiaoMing();//jdk 动态代理对象JDKInvocationHandler jdkInvocationHandler =new JDKInvocationHandler(xiaoMing);//创建Programer 代理对象//创建的代理对象,具备jdkInvocationHandler中的能力Programmer programmer = (Programmer) Proxy.newProxyInstance(XiaoMing.class.getClassLoader(),//真实类new Class[]{Programmer.class},//接口jdkInvocationHandler//动态代理对象);programmer.code(30000);}
}2 Cglib动态代理
因为Spring中已经包含了Cglib库,所以不再重新引入
案例: 日志打印
2.1 自定义Cglib代理工厂
public class CglibProxyFactory 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();}
@Overridepublic Object intercept(Object proxy,Method method,Object[] args,MethodProxy methodProxy) throws Throwable {System.out.println("[cglib]"+method.getName()+"方法被执行,参数:"+ Arrays.toString(args));//执行方法Object result = methodProxy.invokeSuper(proxy, args);System.out.println("cglib,返回值:"+result);return result;}
}2.2 测试
public class CglibTest {public static void main(String[] args) {//真实类WebUserServiceImpl webUserServiceImpl = new WebUserServiceImpl();//工厂类CglibProxyFactory factory = new CglibProxyFactory();//设置真实类WebUserService webUserService = (WebUserService) factory.getInstance(webUserServiceImpl);WebUser webUser = webUserService.findById(99);}
}四.总结
代理模式,代码可以看懂就合格了
重点是能把代理模式描述清楚
有能力了,可以把代码敲一遍
