Java代理机制是一种在运行时创建一个代理对象来代替原始对象的方法。代理对象通常用于在调用原始对象的方法之前或之后执行一些额外的操作,例如日志记录、性能监控等。
静态代理是在编译时就已经确定代理的对象,代理类和原始类是一对一的关系。下面是一个简单的静态代理的例子:
// 定义接口
public interface Hello {
void sayHello();
}
// 原始类
public class HelloImpl implements Hello {
@Override
public void sayHello() {
System.out.println("Hello, world!");
}
}
// 代理类
public class HelloProxy implements Hello {
private Hello hello;
public HelloProxy(Hello hello) {
this.hello = hello;
}
@Override
public void sayHello() {
System.out.println("Before saying hello");
hello.sayHello();
System.out.println("After saying hello");
}
}
动态代理是在运行时创建代理对象,代理类是在运行时生成的。Java提供了java.lang.reflect.Proxy
和java.lang.reflect.InvocationHandler
来实现动态代理。下面是一个简单的动态代理的例子:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
// 定义接口
public interface Hello {
void sayHello();
}
// 原始类
public class HelloImpl implements Hello {
@Override
public void sayHello() {
System.out.println("Hello, world!");
}
}
// 动态代理类
public class DynamicProxy implements InvocationHandler {
private Object target;
public DynamicProxy(Object target) {
this.target = target;
}
public Object getProxy() {
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("Before saying hello");
Object result = method.invoke(target, args);
System.out.println("After saying hello");
return result;
}
}
下面是一个使用CGLIB实现动态代理的示例。
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
// 原始类
public class Hello {
public void sayHello() {
System.out.println("Hello, world!");
}
}
// CGLIB动态代理类
public class CglibProxy implements MethodInterceptor {
private Object target;
public CglibProxy(Object target) {
this.target = target;
}
public Object getProxy() {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(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("Before saying hello");
Object result = proxy.invokeSuper(obj, args);
System.out.println("After saying hello");
return result;
}
}
区别 | JDK代理 | CGLIB代理 |
---|---|---|
实现方式 | 基于接口实现 | 基于继承实现 |
目标对象 | 必须实现接口 | 可以是普通类或接口实现类 |
代理性能 | 通常比CGLIB代理慢 | 通常比JDK代理快 |
适用场景 | 目标对象实现接口的情况 | 目标对象不实现接口或需要继承实现的情况 |
生成代理对象的方式 | Proxy.newProxyInstance() | CGLIB动态生成子类 |
在Spring中,代理通常用于AOP(面向切面编程)和事务管理。Spring使用代理来实现切面的横切逻辑,并且可以通过配置来选择使用静态代理还是动态代理。
Spring提供了两种代理方式:JDK动态代理和CGLIB动态代理。默认情况下,如果目标对象实现了接口,Spring会使用JDK动态代理;如果目标对象没有实现接口,Spring会使用CGLIB动态代理。
在一些情况下,可能不适合使用代理,例如:
在Spring中,代理通常用于AOP
和事务管理
,而在一些特定场景下可能不适合使用代理。这里提出一点,当方法名被private修饰
或者使用this调用方法
不会生成代理类,这可能会导致事务失效
,异步任务错误的执行
等。