设计模式之代理模式
代理模式
- 作用:在不改变原有代码的基础上,增加或扩展额外的功能
- 静态代理
//1,被代理类需要实现的接口,代理类也要实现该接口,该接口对用户使用
interface FlightMachine{
void fly();
}
//2,被代理类实现接口
class FlightMachineImpl implements FlightMachine{
@Override
public void fly() {
System.out.println("我可以飞");
}
}
//3,代理类实现接口
class FlightProxy implements FlightMachine{
//4,代理类引用被代理对象
private FlightMachine flightMachine;
//5,写有参构造方法得到被代理对象实例
public FlightProxy(FlightMachine flightMachine){
super();
this.flightMachine=flightMachine;
}
@Override
public void fly() {
//增加额外的功能
System.out.println("我可以发射导弹");
flightMachine.fly();
//增加额外的功能
System.out.println("我可以航拍");
}
}
public class TestProxy {
public static void main(String[] args) {
FlightMachine flightMachine = new FlightMachineImpl();
FlightMachine flightProxy = new FlightProxy(flightMachine);
flightProxy.fly();
}
}
console:
我可以发射导弹
我可以飞
我可以航拍
小结:代理类和被代理类都需要实现同一个接口,且代理类预先设定,造成服务单一,要是其他类需要代理则需要更多代理类,不易扩展,缺点比较明显,适用场景不广。
- 动态代理
- JDK代理
- 使用JDK自带的代理类,制造代理工厂
- 使用JDK自带的代理类,制造代理工厂
- JDK代理
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
//1,被代理类实现的接口
interface FlightMachine{
void fly();
}
//2,被代理类需要至少实现的一个接口
class FlightMachineImpl implements FlightMachine{
@Override
public void fly() {
System.out.println("我可以飞");
}
}
//3,创建动态代理的工厂类,用来动态生成代理类对象
class FlightProxyFactory{
//4,需要引用被代理的对象
private Object target;
//5,写有参构造方法得到代理目标实例
public FlightProxyFactory(Object target) {
this.target = target;
}
//6,提供一个获取代理类对象的方法
public Object getProxyInstance(){
//用JDK自带的reflect包的Proxy创建代理类实例
/*
@Proxy.newProxyInstance(Param1,Param2,Param3){ }
参数1:类加载器,一般一个项目只有一个类加载器,所以选取比较方便获取的类来getClassLoader()就行
参数2:代理目标所实现的所有接口,通过.getClass().getInterfaces()获得
参数3:方法调用处理器
*/
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), new InvocationHandler() {
/*
invoke(Param1,Param2,Param3){ }
参数1:代理类对象
参数2:被代理类(代理目标)需要执行的方法
参数3:执行方法需要的参数
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//增加额外的功能
System.out.println("我可以发射导弹");
//通过反射来调用代理目标方法
Object procedure = method.invoke(target, args);
//增加额外的功能
System.out.println("我可以航拍");
return procedure;
}
});
}
}
public class TestProxy {
public static void main(String[] args) {
FlightMachine flightMachine = new FlightMachineImpl();
FlightProxyFactory flightProxyFactory = new FlightProxyFactory(flightMachine);
Object proxyInstance = flightProxyFactory.getProxyInstance();
if (proxyInstance instanceof FlightMachine){
FlightMachine machineProxy = (FlightMachine) proxyInstance;
machineProxy.fly();
}
}
}
console:
我可以发射导弹
我可以飞
我可以航拍
小结:建立代理工厂,根据需要的类动态生成代理类,虽然代理目标不固定,但是需要实现至少一个接口,不是所有的类都实现了接口或者继承了某个类,所以还不够好,但是JDK代理在反射生成代理类方面是作用较好,和其他动态代理方式配合使用效果更好。
- CGLIB代理
- 使用第三方代理包,cglib和asm两个包需要引入,核心接口是MethodInterceptor,核心类是Enhancer,给被代理类动态生成一个子类来进行代理(子类对父类来说就相当于扩展了功能)
- 使用第三方代理包,cglib和asm两个包需要引入,核心接口是MethodInterceptor,核心类是Enhancer,给被代理类动态生成一个子类来进行代理(子类对父类来说就相当于扩展了功能)
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
//1,被代理类
class FlightMachineImpl {
public void fly() {
System.out.println("我可以飞");
}
}
//2,创建cglib动态代理的工厂类,用来动态生成代理类、代理类对象,并实现MethodInterceptor接口
class CglibProxyInterceptor implements MethodInterceptor {
//3,引用代理目标的对象
private Object target;
//4,写有参构造方法得到代理目标实例
public CglibProxyInterceptor(Object target) {
this.target = target;
}
//5,提供一个获取代理类对象的方法
public Object getProxyInstance(){
//6,用cglib包的Enhancer创建代理类,且该代理类需要继承代理目标成为其子类
Enhancer enhancer = new Enhancer();
//7,将代理目标设置为代理类的父类
enhancer.setSuperclass(target.getClass());
//8,设置回调函数
enhancer.setCallback(this);
//9,创建代理类对象
return enhancer.create();
}
//6,实现intercept方法
/*
@intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy){ }
参数1 o:被代理的对象
参数2 method:代理对象的方法,这里是FlightMachineImpl的fly()方法
参数3 objects:方法的参数
参数4 methodProxy:方法代理,这里代理的是cglib代理的fly()方法
*/
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("我可以发射导弹");
Object result = method.invoke(target, objects);
System.out.println("我可以航拍");
//methodProxy的invokeSuper可以实现相同的效果
// Object result = methodProxy.invokeSuper(o, objects);
return result;
}
}
public class TestProxy {
public static void main(String[] args) {
CglibProxyInterceptor cglibProxyInterceptor = new CglibProxyInterceptor(new FlightMachineImpl());
Object proxyInstance = cglibProxyInterceptor.getProxyInstance();
if (proxyInstance instanceof FlightMachineImpl){
FlightMachineImpl flightMachine = (FlightMachineImpl) proxyInstance;
flightMachine.fly();
}
}
}
console:
我可以发射导弹
我可以飞
我可以航拍
小结:使用cglib代理,代理目标不用实现接口或继承类,只需根据该被代理类生成子类作为其代理类完成代理,和JDK代理一起在spring aop中使用广泛。