动态代理是相对于静态代理的一个概念。这种情况下,代理类并不是在Java代码中预先定义好的,而是在程序运行时根据我们的在Java代码动态生成的
以下测试代码部分来自于msb基础课程笔记
Overview
Spring动态代理主要分为两种:
Proxy 动态代理: JDK自带的
面向接口:1.没有接口无法使用
2.增强只能增强接口的方法,无法增强接口实现类独有的方法
3.通过反射获取注解只能获取接口的注解,无法获取实现类的注解
cglib 动态代理:需要引入第三方jar包
面向父类:1.不需要接口
2.可以增强父类的所有方法
3.可以读取父类的所有注解
Proxy动态代理:
package com.test.testProxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;
public class Test1 {
public static void main(String[] args) {
Dinner dinner=new Person("张三");
// 通过Porxy动态代理获得一个代理对象,在代理对象中,对某个方法进行增强
// ClassLoader loader,被代理的对象的类加载器
ClassLoader classLoader = dinner.getClass().getClassLoader();
// Class<?>[] interfaces,被代理对象所实现的所有接口
Class[] interaces= dinner.getClass().getInterfaces();
// InvocationHandler h,执行处理器对象,专门用于定义增强的规则
InvocationHandler handler = new InvocationHandler(){
// invoke 当我们让代理对象调用任何方法时,都会触发invoke方法的执行
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// Object proxy, 代理对象,如dinnerProxy
// Method method,被代理的方法,drink/eat方法
// Object[] args,被代理方法运行时的实参,"包子"
Object res=null;
if(method.getName().equals("eat")){
System.out.println("饭前洗手");
// 让原有的eat的方法去运行,注意invoke的调用,是使原有方法正常执行。dinner对象如果搞错会使程序进入死循环
res =method.invoke(dinner, args);
System.out.println("饭后刷碗");
}else{
// 如果是其他方法,那么正常执行就可以了
res =method.invoke(dinner, args);
}
//注意最后的返回值
return res;
}
};
Dinner dinnerProxy =(Dinner) Proxy.newProxyInstance(classLoader,interaces,handler);
//dinnerProxy.eat("包子");
dinnerProxy.drink();
}
}
interface Dinner{
void eat(String foodName);
void drink();
}
class Person implements Dinner{
private String name;
public Person(String name) {
this.name = name;
}
@Override
public void eat(String foodName) {
System.out.println(name+"正在吃"+foodName);
}
@Override
public void drink( ) {
System.out.println(name+"正在喝茶");
}
}
class Student implements Dinner{
private String name;
public Student(String name) {
this.name = name;
}
@Override
public void eat(String foodName) {
System.out.println(name+"正在食堂吃"+foodName);
}
@Override
public void drink( ) {
System.out.println(name+"正在喝可乐");
}
}
Proxy代理主要使用 Proxy.newProxyInstance(classLoader,interaces,handler)方法。
参数列表:1.ClassLoader loader,被代理的对象的类加载器
2.Class<?>[] interfaces,被代理对象所实现的所有接口,注意是个数组
3.InvocationHandler h,执行处理器对象,专门用于定义增强的规则
其中InvocationHandler h的new的实例对象是个匿名内部类,需要重写invoke方法。invoke方法有三个参数:
1.Object proxy, 代理对象
2.Method method,被代理的方法
3.Object[] args,被代理方法运行时的实参,如果没有实参,则为null。
以上三个参数实际上就是被代理对象及对象的一些参数,以便代理时方便使用
CGLIB动态代理:
cglib动态代理的底层设计逻辑是通过自类重写父类方法而实现增强。使用者通过使用Enhancer类来生成子类,而不需要手写子类。通过Enhancer的回调方法(子类的方法)完成代理增强。
package com.msb.testCglib;
import org.junit.Test;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
* @Author: Ma HaiYang
* @Description: MircoMessage:Mark_7001
*/
public class Test1 {
@Test
public void testCglib(){
Person person =new Person();
// 获取一个Person的代理对象
// 1 获得一个Enhancer对象
Enhancer enhancer=new Enhancer();
// 2 设置父类字节码
enhancer.setSuperclass(person.getClass());
// 3 获取MethodIntercepter对象 用于定义增强规则
MethodInterceptor methodInterceptor=new MethodInterceptor() {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
/*Object o, 生成之后的代理对象 personProxy
Method method, 父类中原本要执行的方法 Person>>> eat()
Object[] objects, 方法在调用时传入的实参数组
MethodProxy methodProxy 子类中重写父类的方法 personProxy >>> eat()
*/
Object res =null;
if(method.getName().equals("eat")){
// 如果是eat方法 则增强并运行
System.out.println("饭前洗手");
res=methodProxy.invokeSuper(o,objects);
System.out.println("饭后刷碗");
}else{
// 如果是其他方法 不增强运行
res=methodProxy.invokeSuper(o,objects); // 子类对象方法在执行,默认会调用父类对应被重写的方法
}
return res;
}
};
// 4 设置methodInterceptor
enhancer.setCallback(methodInterceptor);
// 5 获得代理对象
Person personProxy = (Person)enhancer.create();
// 6 使用代理对象完成功能
personProxy.eat("包子");
}
}
class Person {
public Person( ) {
}
public void eat(String foodName) {
System.out.println("张三正在吃"+foodName);
}
}
cglib主要使用Enhancer类,步骤如下:
1. 获得一个Enhancer对象.
2.设置父类字节码(为了创建子类)
3.获取MethodIntercepter对象 用于定义增强规则(子类的回调函数)
4.设置methodInterceptor(设置回调)
5.获得代理对象(生成具体的代理子类)
6.使用代理对象完成功能(使用子类增强,完成代理)
注意MethodIntercepter对象的intercept方法,参数列表4个参数:
1.Object o, 生成之后的代理对象 (子类)personProxy
2.Method method, 父类中原本要执行的方法 Person>>> eat()
3. Object[] objects, 方法在调用时传入的实参数组
4 MethodProxy methodProxy 子类中重写父类的方法 personProxy >>> eat()
其中通过methodProxy.invokeSuper(o,objects)调用父类方法。