JDK动态代理

Java中的两种常用动态代理方式

JDK动态代理和Cglib动态代理是Java中常用的实现动态代理的方式。它们都可以在运行时生成代理类,实现对目标对象的代理操作。

JDK动态代理适用于接口代理,Cglib动态代理适用于类代理。

Cglib动态代理

Cglib动态代理是基于继承的动态代理方式。它通过生成目标类的子类来实现代理,子类重写了目标类的方法,并在方法中添加了代理逻辑。


JDK动态代理

JDK动态代理是Java提供的一种基于接口的动态代理方式。它通过反射机制在运行时动态生成代理类,代理类实现了目标接口,并且将方法的调用委托给InvocationHandler接口的实现类来处理。

  1. 基于接口的动态代理示例代码:
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();
    }
}
  1. 基于类的动态代理示例代码:
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()方法创建代理对象时,需传三个参数:

  1. 类加载器(ClassLoader):用来加载目标类和代理类的类加载器。一般情况下,可以使用目标类的类加载器来加载代理类。

  2. 接口数组(Class<?>[] interfaces):代理类需要实现的接口数组。代理对象会实现这些接口,并且可以调用接口中定义的方法。

  3. 调用处理器(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 中,我们可以实现代理逻辑,例如在方法调用前后打印日志、记录方法执行时间等等。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

路西法98

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值