Java代理是一种设计模式,它允许在不改变原始类或接口的情况下对其进行增强或修改。
假设我们有一个名为 UserService接口和实现类,它提供了两个方法 addUser 和 deleteUser
public interface UserService {
public void addUser(String name);
public void deleteUser(String name);
}
public class UserServiceImpl implements UserService{
@Override
public void addUser(String name) {
System.out.println("添加用户:" + name);
}
@Override
public void deleteUser(String name) {
System.out.println("删除用户:" + name);
}
}
现在,我们需要在 addUser 和 deleteUser 方法执行前后打印日志。一种实现方式是在每个方法的前后都打印日志,如下所示:
public class UserServiceImpl implements UserService{
@Override
public void addUser(String name) {
System.out.println("Before addUser");
System.out.println("添加用户:" + name);
System.out.println("After addUser");
}
@Override
public void deleteUser(String name) {
System.out.println("Before deleteUser");
System.out.println("删除用户:" + name);
System.out.println("After deleteUser");
}
}
虽然上面的方式可以实现对象增强,但它缺点也很明显,增强逻辑与目标方法紧密耦合在一起,侵入性较高,不易扩展和维护。
代理模式可以在不修改原有代码的情况下,增加额外的功能或者对原有功能进行增强。代理模式能够更好的解耦:代理对象和被代理对象是相互独立的,这意味着我们可以在不影响被代理对象的情况下,对代理对象进行修改和优化。
静态代理是在编译时创建的代理对象,需要手动编写代理类。它需要实现与原始类相同的接口,并在代理类中调用原始类的方法。
/**
* Create by zjg on 2024/2/14
* 接口类
*/
public interface UserService {
void addUser(String name);
}
/**
* Create by zjg on 2024/2/14
* 实现类
*/
public class UserServiceImpl implements UserService {
@Override
public void addUser(String name) {
System.out.println("添加用户:" + name);
}
}
/**
* Create by zjg on 2024/2/14
* 代理类
*/
public class UserServiceProxy implements UserService {
private UserService userService;
public UserServiceProxy(UserService userService) {
this.userService = userService;
}
@Override
public void addUser(String name) {
System.out.println("添加用户之前的日志记录");
userService.addUser(name);
System.out.println("添加用户之后的日志记录");
}
}
/**
* Create by zjg on 2024/2/14
* 测试类
*/
public class UserServiceTest {
// 使用代理
public static void main(String[] args) {
UserService userService = new UserServiceImpl();
UserService proxy = new UserServiceProxy(userService);
proxy.addUser("张三");
}
}
为了解决静态代理的问题,我们使用动态代理。动态代理可以通过Java的反射机制在运行时动态地生成代理类,无需手动编写代理类。动态代理可以代理多个接口,且可以实现通用的代理逻辑,避免了代码重复,同时也避免了静态代理中需要手动编写代理类的缺点。
jdk动态代理是通过2个类:java.lang.reflect.Proxy、java.lang.reflect.InvocationHandler来实现的。
/**
* Create by zjg on 2024/2/14
* 接口类
*/
public interface UserService {
void addUser(String name);
}
/**
* Create by zjg on 2024/2/14
* 实现类
*/
public class UserServiceImpl implements UserService {
@Override
public void addUser(String name) {
System.out.println("添加用户:" + name);
}
}
/**
* Create by zjg on 2024/2/14
* 拦截器类
*/
public class UserServiceInvocationHandler implements InvocationHandler {
private Object target;
public UserServiceInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 执行增强逻辑
System.out.println("方法执行前的日志记录");
// 调用目标方法
Object result = method.invoke(target, args);
// 执行增强逻辑
System.out.println("方法执行后的日志记录");
return result;
}
}
/**
* Create by zjg on 2024/2/14
* 代理类
*/
public class UserServiceProxy {
public static Object getProxy(Object target) {
return Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new UserServiceInvocationHandler(target));
}
}
/**
* Create by zjg on 2024/2/14
* 测试类
*/
public class UserServiceTest {
public static void main(String[] args) {
UserService userService = new UserServiceImpl();
UserService proxy = (UserService) UserServiceProxy.getProxy(userService);
proxy.addUser("张三");
}
}
JDK动态代理的优点在于可以代理任意实现了接口的类,不需要针对特定的类编写代理代码。但是,它只能代理实现了接口的类,无法代理没有实现接口的类。
相比于JDK动态代理,CGLib可以对任意类进行代理,而不仅仅是接口。
<dependency>
<groupId>cglibgroupId>
<artifactId>cglibartifactId>
<version>3.3.0version>
dependency>
/**
* Create by zjg on 2024/2/14
* 接口类
*/
public interface UserService {
void addUser(String name);
}
/**
* Create by zjg on 2024/2/14
* 实现类
*/
public class UserServiceImpl implements UserService {
@Override
public void addUser(String name) {
System.out.println("添加用户:" + name);
}
}
/**
* Create by zjg on 2024/2/14
* 拦截器类
*/
public class UserServiceMethodInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
// 执行增强逻辑
System.out.println("方法执行前的日志记录");
// 调用目标方法
Object result = proxy.invokeSuper(obj, args);
// 执行增强逻辑
System.out.println("方法执行后的日志记录");
return result;
}
}
/**
* Create by zjg on 2024/2/14
* 代理类
*/
public class UserServiceProxy {
public static Object getProxy(Class<?> clazz) {
//1.创建Enhancer对象
Enhancer enhancer = new Enhancer();
//2.通过setSuperclass来设置父类型,即需要给哪个类创建代理类
enhancer.setSuperclass(clazz);
/*3.设置回调,需实现org.springframework.cglib.proxy.Callback接口,
此处使用的是org.springframework.cglib.proxy.MethodInterceptor,也是一个接口,实现了Callback接口,
当调用代理对象的任何方法的时候,都会被MethodInterceptor接口的invoke方法处理*/
enhancer.setCallback(new UserServiceMethodInterceptor());
//4.获取代理对象,调用enhancer.create方法获取代理对象,这个方法返回的是Object类型.
return enhancer.create();
}
}
/**
* Create by zjg on 2024/2/14
* 测试类
*/
public class UserServiceTest {
public static void main(String[] args) {
//方法返回的是Object类型,需要转型
UserService userService = (UserService) UserServiceProxy.getProxy(UserServiceImpl.class);
userService.addUser("张三");
}
}
回到顶部
以上内容仅为java中代理模式的简单实现,具体原理和更详细的介绍请查看原博客