Java中的两种常用动态代理方式
JDK动态代理和Cglib动态代理是Java中常用的实现动态代理的方式。它们都可以在运行时生成代理类,实现对目标对象的代理操作。
JDK动态代理适用于接口代理,Cglib动态代理适用于类代理。
Cglib动态代理
Cglib动态代理是基于继承的动态代理方式。它通过生成目标类的子类来实现代理,子类重写了目标类的方法,并在方法中添加了代理逻辑。
JDK动态代理
JDK动态代理是Java提供的一种基于接口的动态代理方式。它通过反射机制在运行时动态生成代理类,代理类实现了目标接口,并且将方法的调用委托给InvocationHandler接口的实现类来处理。
- 基于接口的动态代理示例代码:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
// 定义接口
interface Hello {
void sayHello();
}
// 实现接口的类
class HelloImpl implements Hello {
@Override
public void sayHello() {
System.out.println("Hello, World!");
}
}
// 实现InvocationHandler接口
class DynamicProxy implements InvocationHandler {
private Object target;
public DynamicProxy(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("Before method invocation");
Object result = method.invoke(target, args);
System.out.println("After method invocation");
return result;
}
}
public class Main {
public static void main(String[] args) {
Hello hello = new HelloImpl();
InvocationHandler handler = new DynamicProxy(hello);
Hello proxy = (Hello) Proxy.newProxyInstance(
hello.getClass().getClassLoader(),
hello.getClass().getInterfaces(),
handler);
proxy.sayHello();
}
}
- 基于类的动态代理示例代码:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
// 定义类
class Hello {
public void sayHello() {
System.out.println("Hello, World!");
}
}
// 实现InvocationHandler接口
class DynamicProxy implements InvocationHandler {
private Object target;
public DynamicProxy(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("Before method invocation");
Object result = method.invoke(target, args);
System.out.println("After method invocation");
return result;
}
}
public class Main {
public static void main(String[] args) {
Hello hello = new Hello();
InvocationHandler handler = new DynamicProxy(hello);
Hello proxy = (Hello) Proxy.newProxyInstance(
hello.getClass().getClassLoader(),
hello.getClass().getInterfaces(),
handler);
proxy.sayHello();
}
}
Java动态代理中,通过Proxy.newProxyInstance()方法创建代理对象时,需传三个参数:
-
类加载器(ClassLoader):用来加载目标类和代理类的类加载器。一般情况下,可以使用目标类的类加载器来加载代理类。
-
接口数组(Class<?>[] interfaces):代理类需要实现的接口数组。代理对象会实现这些接口,并且可以调用接口中定义的方法。
-
调用处理器(InvocationHandler):一个实现了InvocationHandler接口的对象,用来处理代理对象的方法调用。在调用代理对象的方法时,会触发调用处理器的invoke()方法。
第一个参数的类加载器可以传递目标类的类加载器,也可以传递实现了 InvocationHandler
接口的对象的类加载器。但是,为了确保代理类能够访问目标类的方法和属性,通常建议传递目标类的类加载器。
如果接口没有实现类时,情景1,工具类中提供了注解,在服务的接口的方法上,通过使用工具类中的注解就能执行接口方法,而不需要定义接口的实现类。
//服务中有接口
public interface AInter {
public void insetStudent(Student stu);
}
//如何想要AInter能被代理,可把AInter注入到spring中,返回值为代理后的对象,这样@Autowire拿到的就是代理对象,调用AInter中的方法时,走的就是代理对象里面的逻辑
//配置类
@Configuration
public class Config {
@Bean
public AInter doProxy () {
return Util.myProxy(AInter.class)l
}
}
//service层
pubic class StuService {
@Autowire
AInter aInter;
}
------------------------------------------------------
//工具类
public class Util() {
public <T> T myProxy(Class<T> classPro){
MyHandle handler = new MyHandle(classPro);
T proxy = (T) Proxy.newProxyInstance(
handler.getClass().getClassLoader(),
new Class<?>[] {classPro},
handler);
}
return proxy;
}
//实现InvocationHandler接口的类
public class MyHandle implements InvocationHandler{
private Type target;
public MyHandle(Type target) {
this.target = target;
}
}
第一个参数可传入实现了InvocationHandler接口的对象类加载器,第二个参数可直接传入这个接口的数组,第三个参数传实现InvocationHandler接口的对象。
如果接口没有实现类时,情景2:如果没有目标类只有目标接口,并且没有类实现这个目标接口,
roxy.newProxyInstance()三个参数
第一个参数应该传递一个类加载器,这个类加载器可以是任何一个类加载器,因为在这种情况下,代理类并不需要加载目标类,只需要加载目标接口即可。一般情况下,可以使用当前线程的上下文类加载器来加载代理类,即Thread.currentThread().getContextClassLoader()
。如果当前线程的上下文类加载器无法加载代理类,可以尝试使用目标接口的类加载器来加载代理类,即targetInterface.getClassLoader()
。
第二个参数应该传递目标接口的 Class 对象。这样,代理对象就可以实现目标接口,并且可以代理目标接口中的方法调用。
示例代码:
public interface TargetInterface {
void doSomething();
}
public class Main {
public static void main(String[] args) {
TargetInterface proxy = (TargetInterface) Proxy.newProxyInstance(
Main.class.getClassLoader(),
new Class[]{TargetInterface.class},
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 在这里实现代理逻辑
return null;
}
});
proxy.doSomething();
}
}
创建了一个代理对象,实现了 TargetInterface 接口,并且代理了 TargetInterface 中的方法调用。在第二个参数中,我们传递了 TargetInterface.class,这样代理对象就知道它需要实现哪个接口。在 InvocationHandler 中,我们可以实现代理逻辑,例如在方法调用前后打印日志、记录方法执行时间等等。