前言
代理模式是指,为其他对象提供一种代理以控制对这个对象的访问。在某些情况下, 一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户类和目标对象之间起到中介的作用。
一、代理模式的作用
- 功能增强
- 控制访问
二、动态代理
动态代理是指代理类对象在程序运行时由 JVM 根据反射机制动态生成的。动态代理不需要定义代理类的.java 源文件。动态代理其实就是 jdk 运行期间,动态创建 class 字节码并加载到 JVM。
动态代理的实现方式常用的有两种:
JDK 动态代理:使用java反射包中的类和接口实现,反射包java.lang.reflect,里面有三个类:InvocationHandler,Method,Proxy
CGLIB 动态代理:第三方工具库,原理是继承,通过目标类创建子类,子类中重写同名的方法。
jdk动态代理
一、原理
-
反射,Method类,表示方法,类中的方法。通过Method可以执行某个方法。
service接口:
public interface HelloService { void hello(String name); }
实现类:
public class HelloServiceImpl implements HelloService { @Override public void hello(String name) { System.out.println("你好,"+name); } }
反射调用方法:
public class Main { public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { HelloService helloService = new HelloServiceImpl(); //获得的方法名,后面为方法的参数类型 Method hello = HelloService.class.getMethod("hello", String.class); //传入对象和参数,执行结果为一个object Object o = hello.invoke(helloService, "操纪文"); //方法类型返回值void,所以为null System.out.println(o); } }
-
动态代理,使用反射包java.lang.reflect
1)InvocationHandler就一个方法invoke(),把代理对象要执行的代码写在invoke中,从而完成调用目标对象或者功能增强。
源码:public Object invoke(Object proxy, Method method, Object[] args);
参数: Object proxy:jdk创建的代理对象,无需赋值。
Method method:目标类中的方法,jdk提供method对象的
Object[] args:目标类中方法的参数, jdk提供的。使用:1. 创建类实现接口InvocationHandler
2. 重写invoke()方法
2)Method类:表示方法的, 确切的说就是目标类中的方法,通过Method可以执行某个目标类的方法,Method.invoke();
3)Proxy类:核心的对象,创建代理对象。之前创建对象都是 new 类的构造方法(),现在我们是使用Proxy类的方法,代替new的使用。
二、实现
service接口:
public interface UsbSell {
float sell(int amount);
}
实现类:
public class UsbSellImpl implements UsbSell {
@Override
public float sell(int amount) {
return 85.0f;
}
}
创建InvocationHandler接口的实现类,在invoke方法中完成调用目标方法,以及功能增强
public class MySellHandler implements InvocationHandler {
private Object target = null;
//动态代理,要代理的对象是活动的,传入谁,就给谁代理
public MySellHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//执行目标方法
Object invoke = null;
invoke = method.invoke(target, args);
//功能增强,加价
if (null!=invoke){
float res = (float) invoke;
res = res + 25;
invoke = res;
}
//返回价格
return invoke;
}
}
实现动态代理:
public class Main {
public static void main(String[] args) {
//被代理的对象
UsbSell usbSell = new UsbSellImpl();
//InvocationHandler实现类
InvocationHandler handler = new MySellHandler(usbSell);
//proxy创建代理对象
UsbSell u = (UsbSell) Proxy.newProxyInstance(usbSell.getClass().getClassLoader(),
usbSell.getClass().getInterfaces(),
handler);
float sell = u.sell(2);
System.out.println(sell);
}
}
cglib动态代理
一、原理
cglib是针对类来实现代理的,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。
二、实现
首先要导入cglib依赖的jar包,cglib又要依赖asm,这个nodep包就是不需依赖的意思,里面已经包含asm代码。
<!-- https://mvnrepository.com/artifact/cglib/cglib-nodep -->
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib-nodep</artifactId>
<version>3.3.0</version>
</dependency>
接口:
public interface BookFacade {
public void addBook();
}
没有实现接口的实现类:
public class BookFacadeImpl1 {
public void addBook() {
System.out.println("增加图书的普通方法...");
}
}
用cglib动态代理:
public class BookFacadeCglib implements MethodInterceptor {
private Object target;
/**
* 创建代理对象
* @param target
* @return
*/
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 obj, Method method, Object[] args,
MethodProxy proxy) throws Throwable {
System.out.println("事物开始");
proxy.invokeSuper(obj, args);
System.out.println("事物结束");
return null;
}
}
测试:
public class TestCglib {
public static void main(String[] args) {
BookFacadeCglib cglib=new BookFacadeCglib();
BookFacadeImpl1 bookCglib=(BookFacadeImpl1)cglib.getInstance(new BookFacadeImpl1());
bookCglib.addBook();
}
}