spring切面实现的几种方式

👁️ 9759 ❤️ 603
spring切面实现的几种方式

在Spring框架中,实现自定义注解的切面增强主要有三种方式:使用@Aspect注解、编写拦截器切面(如HandlerInterceptor)以及手动生成代理类(如JDK动态代理或CGLIB)。以下是这三种方式的优劣对比及适用场景分析:

1. 使用 @Aspect 注解

实现方式

通过声明式AOP,结合@Aspect、@Pointcut和通知注解(@Before、@Around等)实现。

@Aspect

@Component

public class CustomAnnotationAspect {

@Pointcut("@annotation(com.example.CustomAnnotation)")

public void annotatedMethod() {}

@Around("annotatedMethod()")

public Object handleCustomAnnotation(ProceedingJoinPoint joinPoint) throws Throwable {

// 前置逻辑

Object result = joinPoint.proceed();

// 后置逻辑

return result;

}

}

优点

简单高效:通过注解和切点表达式快速匹配带有自定义注解的方法。

集成度高:天然支持Spring生态(如事务管理、其他切面协作)。

非侵入式:业务代码无需感知切面逻辑,仅需添加注解。

维护方便:集中管理切面逻辑,减少重复代码。

缺点

受限于Spring AOP:仅作用于Spring管理的Bean,无法增强非Spring对象(如new创建的对象)。

代理机制限制:默认对接口使用JDK动态代理,对类使用CGLIB,可能引入性能开销。

作用范围有限:无法直接拦截静态方法或私有方法。

适用场景

通用业务逻辑增强:如日志、事务、权限校验、性能监控。

团队协作项目:标准化切面逻辑,降低维护成本。

2. 编写拦截器切面(如 HandlerInterceptor)

实现方式

通过实现HandlerInterceptor接口拦截Web请求,结合自定义注解标记Controller方法。

@Component

public class CustomAnnotationInterceptor implements HandlerInterceptor {

@Override

public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {

if (handler instanceof HandlerMethod) {

HandlerMethod handlerMethod = (HandlerMethod) handler;

if (handlerMethod.getMethod().isAnnotationPresent(CustomAnnotation.class)) {

// 处理自定义注解逻辑

}

}

return true;

}

}

// 注册拦截器

@Configuration

public class WebConfig implements WebMvcConfigurer {

@Autowired

private CustomAnnotationInterceptor interceptor;

@Override

public void addInterceptors(InterceptorRegistry registry) {

registry.addInterceptor(interceptor).addPathPatterns("/**");

}

}

优点

专注Web层:高效处理HTTP请求/响应,适合URL或Controller方法级别的拦截。

轻量级:直接与Spring MVC集成,无需额外代理机制。

灵活匹配:支持路径匹配和注解检测组合。

缺点

局限于Web层:无法作用于Service、DAO层的方法。

无法拦截非HTTP请求:如RPC调用或内部方法调用。

功能单一:仅支持请求前后处理,无法实现环绕通知等复杂逻辑。

适用场景

Web请求处理:如接口鉴权、请求日志、跨域处理。

需要URL级控制:如黑白名单过滤、请求参数校验。

3. 手动生成代理类(如JDK动态代理/CGLIB)

实现方式

通过编码动态生成代理对象,手动实现代理逻辑。

public class CustomAnnotationProxy implements InvocationHandler {

private final Object target;

public CustomAnnotationProxy(Object target) {

this.target = target;

}

@Override

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

if (method.isAnnotationPresent(CustomAnnotation.class)) {

// 前置逻辑

}

Object result = method.invoke(target, args);

if (method.isAnnotationPresent(CustomAnnotation.class)) {

// 后置逻辑

}

return result;

}

}

// 使用代理

UserService userService = new UserServiceImpl();

UserService proxy = (UserService) Proxy.newProxyInstance(

UserService.class.getClassLoader(),

new Class[]{UserService.class},

new CustomAnnotationProxy(userService)

);

优点

完全控制代理逻辑:可自定义增强逻辑,适用于高度定制化需求。

不依赖Spring:可增强任意对象(包括非Spring管理的对象)。

灵活性极高:支持动态切换代理策略,如按条件启用不同逻辑。

缺点

代码复杂:需手动处理代理创建、方法调用、异常处理。

侵入性强:需修改对象创建方式(如替换为代理对象)。

维护成本高:代理逻辑分散,难以统一管理。

适用场景

非Spring环境:如遗留系统或纯Java应用。

底层框架开发:如RPC客户端、ORM工具。

动态逻辑需求:如运行时按需生成不同代理。

4. 综合对比

维度@Aspect 注解拦截器切面(如 HandlerInterceptor)手动生成代理类实现复杂度⭐(简单)⭐⭐(中等)⭐⭐⭐⭐(复杂)灵活性⭐⭐⭐(满足多数场景)⭐⭐(限于Web层)⭐⭐⭐⭐⭐(完全自主控制)侵入性⭐(无侵入)⭐(无侵入)⭐⭐⭐(需替换对象)性能开销⭐⭐(代理机制轻微损耗)⭐(高效)⭐⭐⭐(依赖实现优化)作用范围Spring Bean方法Web请求(Controller方法)任意对象和方法适用场景通用业务逻辑增强Web层拦截(鉴权、日志 )高度定制化需求、非Spring环境5. 选择建议

优先使用 @Aspect:适用于大多数业务场景,尤其是需要对Spring Bean的方法进行增强时(如事务、日志)。

Web层选择拦截器:若需针对HTTP请求处理(如权限校验、请求日志),使用HandlerInterceptor更直接高效。

手动代理补充复杂需求:仅在需要完全控制代理逻辑、增强非Spring对象或脱离Spring生态时使用。

← 你好,账号锁定了,多长时间自动解锁? 1990年属马的人的五行属什么 →