代理模式
1.代理模式
在代理模式(Proxy Pattern)中,一个类代表另一个类的功能。这种类型的设计模式属于结构型模式。
在代理模式中,我们创建具有现有对象的对象,以便向外界提供功能接口
1.1介绍
意图:在面向对象系统中,有些对象由于某些原因(比如某些操作需要安全控制),直接访问会给使用者或者系统结构带来很多麻烦,我们可以在访问此对象时加上一个对此对象的访问
主要解决:想在访问一个类时做一些控制。
如何解决:增加中间层。
关键代码:实现与被代理类组合。
1.2 应用实例
在访问对象的时候,如果需要鉴权,对访问者进行判断或者进行校验,可以再访问前做一下处理,或者如果需要打印流程日志,可以在访问过程中加入日志,方便判断,代理模式分为静态代理、动态代理
1.3 静态代理
静态代理需要定义接口或者父类,被代理对象与代理对象一起实现相同的接口或者是继承相同父类,这点是它的缺点,不方便扩展,需要加接口时候,所有的实现都要加同样的接口
1.4 动态代理
动态代理它可以直接给某一个目标(被代理 对象)对象(实现了某个或者某些接口)生成一个代理对象,利用的时Proxy中的newInstance反射来实现代理模式
1.4.1 Java.lang.reflect.Proxy类可以直接生成一个代理对象
Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)生成一个代理对象
- 参数1:ClassLoader loader 代理对象的类加载器 一般使用被代理对象的类加载器
- 参数2:Class<?>[] interfaces 代理对象的要实现的接口 一般使用的被代理对象实现的接口
- 参数3:InvocationHandler h (接口)执行处理类
1.4.2 InvocationHandler中的invoke()方法
invoke(Object proxy, Method method, Object[] args)方法:调用代理类的任何方法,此方法都会执行
- 参数1:代理对象(慎用)
- 参数2:当前执行的方法
- 参数3:当前执行的方法运行时传递过来的参数
- 返回值:当前方法执行的返回值
2.静态代理 代码
2.1 定义接口
package com.jzj.design.demo.proxyDesign.staticproxy;
/**
* 方法的接口
*/
public interface IMethodDAO {
void doSomeThing();
}
2.2 原始接口的实现
接口实现
package com.jzj.design.demo.proxyDesign.staticproxy;
public class LocalMethodImpl implements IMethodDAO {
@Override
public void doSomeThing() {
System.out.println("原始的对象 方法调用");
}
}
2.3 静态代理对象实现
实现同一个接口,通过构造函数初始化 代理对象,通过该对象调用,实现方法的调用
package com.jzj.design.demo.proxyDesign.staticproxy;
public class StaticProxyMethod implements IMethodDAO {
private IMethodDAO teachDAO;
/**
* 静态代理 构造函数,初始化 接口对象
*
* @param teachDAO
*/
public StaticProxyMethod(IMethodDAO teachDAO) {
this.teachDAO = teachDAO;
}
@Override
public void doSomeThing() {
System.out.println("静态代理开始 可以加日志、鉴权 等等操作---------------------");
teachDAO.doSomeThing();
System.out.println("静态代理结束、输出日志,访问结束---------------------");
}
}
2.4 静态代理结果
package com.jzj.design.demo.proxyDesign.staticproxy;
public class StaticProxyMain {
public static void main(String[] args) {
IMethodDAO methodDAO = new LocalMethodImpl();
IMethodDAO staticProxy = new StaticProxyMethod(methodDAO);
staticProxy.doSomeThing();
}
}
3.动态代理 代码
3.1 定义接口
package com.jzj.design.demo.proxyDesign.dynamicproxy;
/**
* 老师在教学 接口
*/
public interface ITeachDAO {
void teach();
}
3.2 方法实现
package com.jzj.design.demo.proxyDesign.dynamicproxy;
/**
* 老师在教学 实现
*/
public class TeacherServiceImpl implements ITeachDAO {
@Override
public void teach() {
System.out.println("原始对象,老师在教书");
}
}
3.3 动态代理实现
通过Proxy newInstance 反射构造对象,然后通过 InvocationHandler 来对具体的方法 进行增强处理
package com.jzj.design.demo.proxyDesign.dynamicproxy;
import java.lang.reflect.Proxy;
/**
* 动态代理
*/
public class DynamicTeachProxy {
/**
* 目标对象
*/
private Object target;
//构造器 对目标对象初始化
public DynamicTeachProxy(Object target) {
this.target = target;
}
//给目标对象 反射生成一个代理对象
public Object getProxyInstance() {
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
(proxy, method, args) -> {
System.out.println("--------动态代理- 老师教书前 准备工作--------");
Object value = method.invoke(target, args);
System.out.println("--------动态代理- 老师教书后 收尾工作--------");
return value;
});
}
}
3.4 动态代理结果
package com.jzj.design.demo.proxyDesign.dynamicproxy;
public class DynamicTestMain {
public static void main(String[] args) {
ITeachDAO target = new TeacherServiceImpl();
//给目标对象 创建代理对象
DynamicTeachProxy proxy = new DynamicTeachProxy(target) ;
ITeachDAO proxyObject =(ITeachDAO) proxy.getProxyInstance();
proxyObject.teach();
}
}