Java Service如何用@Before实现所有方法的前置公共逻辑复用?
两种实现方案
方案1:类初始化时仅执行一次(所有方法复用同一结果)
如果公共逻辑的结果是全局通用、不需要随请求变化的,直接用Spring的@PostConstruct注解,在Service实例初始化时执行一次即可:
@Service public class MyClass implements MyInterface { private String stringToFill = ""; // 注入依赖的公共Service private final CommonService commonService; // Spring推荐构造注入 public MyClass(CommonService commonService) { this.commonService = commonService; } @PostConstruct public void doSomeLogic() { // 调用公共Service的逻辑 stringToFill = commonService.getFilledValue(); } @Override public List<?> getAll() { // 直接复用初始化好的stringToFill System.out.println(stringToFill); // 业务逻辑实现... return null; } @Override public Object getId(Long id) { System.out.println(stringToFill); // 业务逻辑实现... return null; } @Override public void create(Object entity) { System.out.println(stringToFill); // 业务逻辑实现... } }
说明
@PostConstruct标注的方法会在Spring完成依赖注入后、实例对外提供服务前执行,整个Bean生命周期仅运行一次。- 适合加载静态配置、初始化固定数据这类不需要频繁更新的公共逻辑。
方案2:每个接口方法执行前都执行(匹配示例@Before效果)
如果公共逻辑需要每次调用接口方法时都执行(比如每次请求都要刷新数据、校验上下文),用Spring AOP实现前置通知:
步骤1:引入AOP依赖(Maven示例)
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency>
步骤2:编写切面类
@Component @Aspect public class MyServiceAspect { private final CommonService commonService; public MyServiceAspect(CommonService commonService) { this.commonService = commonService; } // 定义切点:匹配MyInterface的所有方法 @Pointcut("execution(* com.yourpackage.MyInterface.*(..))") public void myInterfaceMethods() {} // 前置通知:切点方法执行前触发 @Before("myInterfaceMethods()") public void doBefore(JoinPoint joinPoint) { // 获取目标Service实例,设置公共逻辑结果 MyClass targetService = (MyClass) joinPoint.getTarget(); String filledValue = commonService.getFilledValue(); targetService.setStringToFill(filledValue); } }
步骤3:修改Service类
@Service public class MyClass implements MyInterface { private String stringToFill = ""; @Override public List<?> getAll() { System.out.println(stringToFill); // 业务逻辑实现... return null; } @Override public Object getId(Long id) { System.out.println(stringToFill); // 业务逻辑实现... return null; } @Override public void create(Object entity) { System.out.println(stringToFill); // 业务逻辑实现... } // 给切面提供setter方法 public void setStringToFill(String stringToFill) { this.stringToFill = stringToFill; } }
说明
- 切面的
@Before通知会在每个匹配的接口方法执行前触发,完全符合你示例代码的预期效果。 - 适合需要随每次请求更新数据的公共逻辑场景。
额外提示
- 避免手动在每个业务方法开头调用公共方法,这种方式代码冗余且不易维护。
- 注意线程安全:如果
stringToFill是请求级别的变量,不要用类成员变量,改用ThreadLocal存储,或者直接让公共方法返回结果给业务方法使用。
内容的提问来源于stack exchange,提问作者Talenel
相关产品推荐
相关产品推荐

