反射
什么是反射
在运⾏时获得类的信息,创建类的对象,调⽤其中的⽅法和属性。
反射的作用
- 动态代理
- 框架的实现(Spring、Spring Boot、MyBatis)
- 注解
- 提高了代码灵活性
获取 Class 类对象的 4 种方法
// 已知类
// 通过此方式获取 Class 对象不会进行初始化
Class userClass = User.class;
// 对象
// User user = new User();
Class userClass = user.getClass();
// 类的全路径
Class userClass = Class.forName("cn.wmhwiki.User")
// 类加载器
// 通过此方式获取 Class 对象不会进行初始化
Class userClass = ClassLoader.getSystemClassLoader().loadClass("cn.wmhwiki.User");
动态代理
静态代理实现
- 定义接口
public interface Animal {
void makeSound();
}
- 实现接口
public class Dog implements Animal {
@Override
public void makeSound() {
System.out.println("Woof!");
}
}
- 创建代理类
public class AnimalProxy implements Animal {
private Animal animal;
public AnimalProxy(Animal animal) {
this.animal = animal;
}
@Override
public void makeSound() {
System.out.println("Before making sound...");
animal.makeSound();
System.out.println("After making sound...");
}
}
- 使用代理类
public class StaticProxyDemo {
public static void main(String[] args) {
AnimalProxy animalProxy = new AnimalProxy(new Dog());
animalProxy.makeSound();
}
}
JDK 动态代理实现
-
创建接口,创建原始类实现接口
-
创建动态代理处理器,实现
InvocationHandler
接口,重写invoke()
方法 -
创建原始对象和动态代理处理器对象。
-
使用
Proxy.newProxyInstance()
方法将使用代理对象和动态代理处理器对象创建代理对象。 -
定义接口
public interface Animal {
void makeSound();
}
- 实现接口
public class Dog implements Animal {
@Override
public void makeSound() {
System.out.println("Woof!");
}
}
- 创建动态代理处理器,实现
InvocationHandler
接口
public class AnimalInvocationHandler implements InvocationHandler {
private Object target;
public AnimalInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("Before making sound...");
Object result = method.invoke(target, args);
System.out.println("After making sound...");
return result;
}
}
- 创建并使用代理类
public class Main {
public static void main(String[] args) {
Animal dog = new Dog();
AnimalInvocationHandler handler = new AnimalInvocationHandler(dog);
Animal proxy = (Animal) Proxy.newProxyInstance(
// 原始类的 ClassLoader 对
象
Animal.class.getClassLoader(),
// 原始对象所实行的接口
dog.getClass().getInterfaces(),
// 关联代理对象
handler
);
proxy.makeSound();
}
}
CGLIB 动态代理实现
-
创建原始类
-
创建方法拦截器,并实现
MethodInterceptor
接口 -
使用
Enhancer
类来设置被代理类和回调方法拦截器,创建代理对象 -
创建原始类
public class Dog {
public void makeSound() {
System.out.println("Woof!");
}
}
- 创建方法拦截器,并实现
MethodInterceptor
接口
public class MyMethodInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("Before method execution");
Object result = proxy.invokeSuper(obj, args);
System.out.println("After method execution");
return result;
}
}
- 创建
Enhancer
对象并配置,并创建代理对象。
public class Main {
public static void main(String[] args) {
// 创建 Enhancer 对象
Enhancer enhancer = new Enhancer();
// 设置原始类
enhancer.setSuperclass(Dog.class);
// 设置回调方法拦截器为 MyMethodInterceptor
enhancer.setCallback(new MyMethodInterceptor());
// 创建代理对象
Dog proxy = (Dog) enhancer.create();
// 调用代理对象的方法
proxy.makeSound();
}
}
JDK 动态代理和 CGLIB 动态代理的差异?
- 实现⽅式
- JDK:反射
- CGLIB:继承⽬标类
- ⽬标类限制
- JDK:⽬标类必须要实现接⼝
- CGLIB:没有限制。
- 性能:JDK 动态代理相对于 CGLIB 动态代理较低
- 对象类型:
- JDK:只能代理实现了接⼝的类
- CGLIB:通过继承实现,不能代理 final 类
- 依赖库:
- JDK: Java ⾃带的库,不需要额外的依赖
- CGLIB :依赖 cglib 库