Java案例如何实现服务自服务?

wen python案例 2

本文目录导读:

Java案例如何实现服务自服务?

  1. 在同一个类中调用自己的方法(最基础)
  2. 使用Spring的@Autowired注入自身(解决AOP失效)
  3. 使用ApplicationContext.getBean()获取代理对象
  4. 使用AopContext.currentProxy()(Spring AOP)
  5. 异步自调用(@Async与自服务)
  6. 纯Java中的“自服务”设计(不依赖框架)
  7. 循环自调用(递归)
  8. 总结:选择哪种方式?

在Java中实现“服务自服务”(即一个服务调用自身的方法或逻辑)通常有以下几种常见的场景和实现方式,根据具体的技术栈(如Spring、纯Java等)和业务需求,可以选择不同的方案。

以下是几种典型的实现方式:


在同一个类中调用自己的方法(最基础)

这是最直观的方式,直接调用类自己的方法,但需要注意事务、AOP代理等问题。

public class UserService {
    public void processUser(Long userId) {
        // 业务逻辑
        System.out.println("处理用户: " + userId);
        // 自服务:调用自己的另一个方法
        this.sendNotification(userId); // 直接调用
    }
    public void sendNotification(Long userId) {
        System.out.println("发送通知给用户: " + userId);
    }
}

问题:如果使用了AOP(如@Transactional@Cacheable等),直接通过this调用会导致代理失效,AOP切面不会执行。


使用Spring的@Autowired注入自身(解决AOP失效)

在Spring中,如果希望同一个类中的方法调用能触发AOP(如事务、缓存),需要注入自己(即代理对象)。

@Component
public class UserService {
    @Autowired
    private UserService self; // 注入代理对象
    @Transactional
    public void processUser(Long userId) {
        System.out.println("处理用户: " + userId);
        // 通过代理对象调用,事务/缓存等AOP生效
        self.sendNotification(userId);
    }
    @Transactional(propagation = Propagation.REQUIRES_NEW) // 独立事务
    public void sendNotification(Long userId) {
        System.out.println("发送通知给用户: " + userId);
        // 如果有数据库操作,这里可以开启新事务
    }
}

关键点

  • 注入self(这个变量名可以随意,但推荐用selfthisProxy
  • 所有需要走AOP的方法调用都必须通过self.xxx(),而不是this.xxx()
  • 适用于Spring单例Bean

使用ApplicationContext.getBean()获取代理对象

如果不方便使用字段注入(比如在构造器中需要自调用),可以从ApplicationContext获取Bean。

@Component
public class UserService implements ApplicationContextAware {
    private ApplicationContext applicationContext;
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }
    @Transactional
    public void processUser(Long userId) {
        UserService proxy = applicationContext.getBean(UserService.class);
        proxy.sendNotification(userId);
    }
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void sendNotification(Long userId) {
        System.out.println("发送通知给用户: " + userId);
    }
}

使用AopContext.currentProxy()(Spring AOP)

Spring AOP提供了AopContext.currentProxy()来获取当前代理对象,需要手动开启exposeProxy

@Component
public class UserService {
    @Transactional
    public void processUser(Long userId) {
        // 需要确保配置了 exposeProxy=true
        UserService proxy = (UserService) AopContext.currentProxy();
        proxy.sendNotification(userId);
    }
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void sendNotification(Long userId) {
        System.out.println("发送通知给用户: " + userId);
    }
}

配置(如果是Spring Boot自动配置,需要手动开启):

# application.properties
spring.aop.proxy-target-class=true
spring.aop.expose-proxy=true

或者通过@EnableAspectJAutoProxy(exposeProxy = true)注解。


异步自调用(@Async与自服务)

当需要异步执行自己的方法时,也需要使用代理对象,否则异步不会生效。

@Component
public class NotificationService {
    @Autowired
    private NotificationService self;
    public void sendBatchNotifications() {
        // 异步调用自己的方法
        self.sendSingleNotification("user@example.com");
        System.out.println("异步任务已提交");
    }
    @Async
    public void sendSingleNotification(String email) {
        // 实际发送邮件...
        System.out.println("异步发送邮件到: " + email);
    }
}

纯Java中的“自服务”设计(不依赖框架)

如果不使用Spring,可以通过接口 + 实现类 + 手动代理来实现类似效果。

// 1. 定义接口
interface UserService {
    void processUser(Long userId);
    void sendNotification(Long userId);
}
// 2. 实现类
class UserServiceImpl implements UserService {
    private UserService self; // 代理对象(由外部设置)
    public void setSelf(UserService self) {
        this.self = self;
    }
    @Override
    public void processUser(Long userId) {
        System.out.println("处理用户");
        self.sendNotification(userId); // 通过代理调用
    }
    @Override
    public void sendNotification(Long userId) {
        System.out.println("发送通知");
    }
}
// 3. 手动创建JDK动态代理
public class Main {
    public static void main(String[] args) {
        UserServiceImpl target = new UserServiceImpl();
        UserService proxy = (UserService) Proxy.newProxyInstance(
            Main.class.getClassLoader(),
            new Class[]{UserService.class},
            (obj, method, params) -> {
                System.out.println("前置增强");
                Object result = method.invoke(target, params);
                System.out.println("后置增强");
                return result;
            }
        );
        target.setSelf(proxy); // 设置代理到自身
        proxy.processUser(1L);
    }
}

循环自调用(递归)

自服务”是指递归调用(如树形结构遍历),则直接使用递归即可,无需特殊处理。

public class MenuService {
    public List<Menu> buildTree(List<Menu> allMenus, Long parentId) {
        List<Menu> children = new ArrayList<>();
        for (Menu menu : allMenus) {
            if (menu.getParentId().equals(parentId)) {
                menu.setChildren(buildTree(allMenus, menu.getId())); // 递归
                children.add(menu);
            }
        }
        return children;
    }
}

选择哪种方式?

场景 推荐方式 原因
无事务/AOP需求,纯逻辑 this.xxx() 直接调用 最简单
Spring + 需要事务/缓存/AOP @Autowired注入自身 最常用,清晰
异步自调用 (@Async) 注入自身或AopContext 确保异步生效
无法使用字段注入(如构造器) ApplicationContext.getBean() 灵活
不依赖Spring,纯Java 手动代理 + 设置self 完全控制
递归算法 递归调用 标准做法

最推荐的Spring实现

@Service
public class OrderService {
    @Autowired
    private OrderService self; // 注入代理
    @Transactional
    public void placeOrder(Order order) {
        // 订单逻辑
        self.processPayment(order); // 走代理,事务AOP生效
    }
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void processPayment(Order order) {
        // 支付逻辑(独立事务)
    }
}

这样既保持了代码的简洁性,又确保了框架特性(事务、AOP)的正确发挥。

抱歉,评论功能暂时关闭!