动态代理与@Async注解

动态代理与@Async注解

AOP

Aspect-Oriented Programming,面向切面编程,底层用动态代理实现

动态代理

有两种方式:JDK动态代理和CGLIB动态代理。

JDK动态代理

基于接口实现,JDK会创建一个实现目标对象接口的类作为代理对象。

JDK动态代理逻辑

CGLIB动态代理

基于类实现,生成子类代理对象

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();
    }

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
@Async注解Spring框架中用于标识一个方法是异步执行的。然而,使用@Async注解可能会带来一些潜在的危害。 首先,使用@Async注解需要在配置类上添加@EnableAsync注解,以激活异步功能。这就意味着在使用@Async注解之前,需要对配置进行一些修改,可能会增加代码复杂性和维护成本。 其次,@Async注解是通过AsyncAnnotationBeanPostProcessor这个类实现的。这个类会处理@Async注解并生成代理对象。然而,使用@Async注解后,生成的代理对象与早期暴露出去的对象可能不一样。这可能导致一些问题,比如AOP切面无法正确拦截异步方法的调用。 另外,使用@Async注解需要使用线程池来实现异步执行。虽然可以自己通过线程池来实现异步,但是需要手动管理线程池的创建和销毁。如果线程池的配置不当,可能会导致系统的资源消耗过大或线程池满载而导致请求阻塞。 综上所述,使用@Async注解可能会引入一些潜在的危害,需要在配置和线程池管理方面进行额外的注意和处理。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [@Async注解的坑,小心](https://blog.csdn.net/YYniannian/article/details/125737301)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *3* [Spring中异步注解@Async的使用、原理及使用时可能导致的问题](https://blog.csdn.net/qq_41907991/article/details/107500036)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值