动态代理与@Async注解
AOP
Aspect-Oriented Programming,面向切面编程,底层用动态代理实现
动态代理
有两种方式:JDK动态代理和CGLIB动态代理。
JDK动态代理
基于接口实现,JDK会创建一个实现目标对象接口的类作为代理对象。
CGLIB动态代理
基于类实现,生成子类代理对象
@Async注解
在 Spring Framework 3.0 版本中引入的,用于实现异步操作
注解失效场景:
-
注解未被正确配置
为了使 @Async 注解生效,需要在 Spring 应用程序中启用异步支持,通常是通过在配置类上添加 @EnableAsync 注解来实现。如果未正确配置异步支持,则 @Async 注解将无效。 -
自我调用
如果一个方法在同一类中自我调用,即方法内部通过 this 关键字调用了另一个带有 @Async 注解的方法,那么 @Async 注解将不会生效。这是因为 Spring 使用代理来实现异步调用,自我调用无法触发代理,因此异步功能将无法生效。 -
异步方法的返回值
@Async 注解的方法通常应该返回 void 或 Future(或其子类)类型。如果方法返回类型为 Future,则可以通过 Future 对象获取异步操作的结果。如果返回其他类型(如 String、int 等),则 @Async 注解将失效,方法将同步执行。 -
方法未通过 Spring 容器调用
只有通过 Spring 容器获取的代理对象才会应用切面逻辑和异步功能。如果通过 new 关键字直接创建目标对象的实例并调用带有 @Async 注解的方法,那么异步功能将不会生效。 -
异步线程池未正确配置
异步方法的执行依赖于异步线程池的配置。如果异步线程池未正确配置或不可用,@Async 注解可能会失效。 -
异常处理问题
如果异步方法内部发生异常且未进行适当的异常处理,那么 @Async 注解可能会失效。异常抛出后,异步线程可能会终止,导致异步方法无法完成执行。
对于自我调用失效场景是最容易被忽略的,@Async注解实现的逻辑是:
Spring在扫描所有Bean时,如果发现方法或者类上面有@Async注解,会自动为该类创建一个代理对象,并重写带有@Async注解的方法。如果调用方和被调用方在同一个类里面的话,则不会调用代理对象的方法,调用的依旧是本类中的方法,即不会进行异步操作
附 动态代理(JDK)实现
接口
public interface IUserService {
void add();
void delete();
}
实现类
public class UserServiceImpl implements IUserService {
@Override
public void add() {
System.out.println("添加用户操作");
}
@Override
public void delete() {
System.out.println("删除用户操作");
}
}
增强实现类
public class InvocationHandlerImpl implements InvocationHandler {
/**
* 被代理对象
*/
private Object target;
public InvocationHandlerImpl(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("执行 " + method.getName() + " 方法开始");
// 开始执行
Object result = method.invoke(target, args);
System.out.println("执行 " + method.getName() + " 方法结束");
return result;
}
}
代理工厂
public class ProxyFactory {
/**
* 被代理类
*/
private Object target;
public ProxyFactory(Object target) {
this.target = target;
}
/**
* Proxy.newInstance()方法具体的参数:
* ClassLoader 代理类的类加载器, 也可以使用被代理类的加载器
* interfaces 代理类所实现的接口, 也可以使用被代理类所实现的所有接口
* InvocationHandler 用于拦截和实现具体的方法
*/
public Object getProxy() {
// 类加载器
ClassLoader classLoader = target.getClass().getClassLoader();
// interfaces
Class<?>[] interfaces = target.getClass().getInterfaces();
// 实现逻辑
InvocationHandler invocationHandler = new InvocationHandlerImpl(target);
return Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);
}
}
测试
public class ProxyTest {
public static void main(String[] args) {
// 定义代理工厂
ProxyFactory proxyFactory = new ProxyFactory(new UserServiceImpl());
// 获取代理对象
IUserService userService = (IUserService) proxyFactory.getProxy();
// 逻辑实现
userService.add();
}
}