概括
代理是一种设计模式,提供了对目标对象另外的访问方式;即通过代理对象访问目标对象。这样的好处是可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象功能 – 开闭原则
Java中的代理模式
给目标对象提供一个代理对象,并由代理对象控制对目标对象的引用
目的:
- 通过代理对象间接访问目标对象,防止直接访问目标对象给系统带来复杂性
- 通过代理业务对原有业务进行增强操作
创建代理对象的方式
静态代理
实现目标对象接口或者直接继承目标类,完成逻辑的修改 — 通常使用实现接口方式
我们在实现接口的时候,目标类和代理类都必须实现目标接口当中所实现的方法,从某种意义上代理类可以帮助我们实现目标类中的方法,并且代理类还可以有自己的扩展
package com.proxy;
public class StacticProxy {
public static void main(String[] args) {
new Driver(new You()).driveCar();
}
}
interface Drive{
void driveCar();
}
//真实角色,谁去开车
class You implements Drive{
@Override
public void driveCar() {
System.out.println("简简单单开个车");
}
}
//代理角色,帮助你洗车和加油 真实对象只负责开车
class Driver implements Drive{
//代理谁-->真实目标对象
private Drive drive;
public Driver (Drive drive) {
this.drive= drive;
}
@Override
public void driveCar() {
washCar();
this.drive.driveCar();//真实对象
fuelTheCar();
}
private void washCar() {
System.out.println("洗个车");
}
private void fuelTheCar() {
System.out.println("加个油");
}
}
总结
- 真实对象和代理对象要实现同一个接口
- 代理对象要代理真实角色
好处:
- 代理对象可以做很多真实对象做不了的事情
- 真实对象专注做自己的事情
基于JDK接口的动态代理
JDK代理,实际上是对Java接口的处理,而且只能是对接口进行代理,达到效果是,当调用指定接口的指定方法时,会执行特定操作。如:HelloService是一个接口,public String sayHello(String msg)是该接口的一个方法,当代码调用该接口的sayHello方法时,会执行规定好的动作。
这里HelloService接口的实现类是由代理动态生成的实现类。所以想为一个接口生成代理,需要先生成一个代理对象。
生成代理对象,需要 代理的接口 以及 java.lang.reflect.InvocationHandler的实现类
- 定义接口
public interface HelloService{
String sayHello(String msg);
}
- 创建代理类
public class DefaultInvocation implements InvocationHandler {
public Object invoke(Object proxy,Method,Object[] args) throws Throwable{
System.out.println("被代理的接口方法:" + method);
System.out.println("被代理的接口方法的入参:" + args);
Class<?> clazz = method.getDeclaringClass();
if("com.sunsc.service.HelloService".equals(clazz.getName())&&"sayHello".equals(method.getName()){
return " hello , receive " + args[0];
}
return null;
}
}
- 生成接口的代理对象
生成代理对象,通过调用Proxy.newProxyInstance(ClassLoader loader,class<?>[] interfaces,InvocationHandler h) 方法即可
ClassLoader 要加载代理对象类的类加载器
Class<?> 要被代理的接口集
InvocationHandler h - InvocationHandler的实现类,调用代理对象的方式时,实际上都是执行了该实现类的invoke方法
public static HelloService getHelloService() {
// InvocationHandler的实现类
InvocationHandler invocationHandler = new DefaultInvocation();
// 要加载代理对象类的类加载器
ClassLoader classLoader = HelloService.class.getClassLoader();
// 要被代理的接口
Class<?>[] interfaces = new Class<?>[] { HelloService.class };
// 生成HelloService接口的代理对象
HelloService helloService = (HelloService) Proxy.newProxyInstance(
classLoader, interfaces, invocationHandler);
return helloService;
}
- 通过代理对象调用接口
public static void main(String[] args) {
HelloService helloService = getHelloService();
String result = helloService.sayHello("hello, test");
System.out.println("result: " + result);
}
public static HelloService getHelloService() {
// InvocationHandler的实现类
InvocationHandler invocationHandler = new DefaultInvocation();
// 要加载代理对象类的类加载器
ClassLoader classLoader = HelloService.class.getClassLoader();
// 要被代理的接口
Class<?>[] interfaces = new Class<?>[] { HelloService.class };
// 生成HelloService接口的代理对象
HelloService helloService = (HelloService) Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);
return helloService;
}
基于CGLIB父类的动态代理
当我们需要给没有实现接口的目标类生成代理对象时,jdk的动态代理就完成不了这样的事情了,这时我们就可以继承目标类,以目标类的子类方式实现,这样的方法叫做cglib的动态代理,也可以叫做子类代理,它是在内存中构建一个子类对象从而对目标对象进行功能的增强
// 目标对象
public class HelloService {
public void sayHello(){
System.out.println("hello");
}
}
// 基于cglib实现的动态代理
public class CglibProxyHelloFactory implements MethodInterceptor {
// 目标对象
private Object target;
public CglibProxyHelloFactory(Object target){
this.target = target;
}
@Override
public Object intercept(Object arg0,Method method,Object[] objects,MethodProxy arg3) throws Throwable{
System.out.println("cglib 代理前逻辑");
// 目标对象的目标方法
method.invoke(target,objects);
System.out.println("cglib 代理后逻辑");
return null;
}
}
// 测试类
public class MainTest {
public static void main(String[] args) {
new CglibProxyFactory(new HelloService ()).sayHello();
}
}