RequestAttributes
RequestAttributes 是 Spring 框架中的一个接口,用于在请求的生命周期内存储和访问与当前请求相关的属性。它通常用于处理 Web 应用程序中的请求范围数据,如会话信息、请求参数等。
主要特点
-
作用域:
RequestAttributes提供了一种在整个请求过程中共享数据的方式。这些数据可以在控制器、拦截器或任何其他组件中访问。
-
实现类:
- Spring 提供了多种实现,包括
ServletRequestAttributes和SessionAttributes,分别对应于 HTTP 请求和会话的上下文。
- Spring 提供了多种实现,包括
-
线程安全:
RequestAttributes的设计是线程安全的,因为每个请求都在独立的线程中处理,确保不会出现并发问题。
常用方法
以下是 RequestAttributes 接口的一些常用方法:
-
获取属性:
Object getAttribute(String name, int scope);用于根据名称和作用域(如请求、会话)获取属性值。
-
设置属性:
void setAttribute(String name, Object value, int scope);用于设置属性值,指定其作用域(如 REQUEST_SCOPE 或 SESSION_SCOPE)。
-
移除属性:
void removeAttribute(String name, int scope);根据名称和作用域移除属性。
-
获取所有属性名:
String[] getAttributeNames(int scope);
使用示例
下面是一个简单的示例,展示如何使用 RequestAttributes 在 Spring MVC 中存储和检索数据:
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
@RestController
public class MyController {
@GetMapping("setAttribute")
public void setAttribute() {
RequestContextHolder.currentRequestAttributes().setAttribute("name", "张三zs", RequestAttributes.SCOPE_REQUEST);
RequestContextHolder.currentRequestAttributes().setAttribute("age", 18, RequestAttributes.SCOPE_SESSION);
}
@GetMapping("getAttribute")
public String getAttribute(String key) {
if(StrUtil.equals("name", key)) {
return ObjUtil.toString(RequestContextHolder.getRequestAttributes().getAttribute(key,
RequestAttributes.SCOPE_REQUEST));
} else {
return ObjUtil.toString(RequestContextHolder.getRequestAttributes().getAttribute(key,
RequestAttributes.SCOPE_SESSION));
}
}
}
注意事项
-
作用域选择:确保选择正确的作用域。当你需要在多个请求之间共享数据时,可以考虑使用会话(SESSION_SCOPE),而不是仅限于单个请求(REQUEST_SCOPE)。
-
清理资源:当不再需要某个属性时,应及时调用
removeAttribute()方法,以防止内存泄漏或意外的数据持久化。 -
Spring Boot 支持:如果你使用的是 Spring Boot,
RequestContextHolder和RequestAttributes将自动配置,无需额外配置即可直接使用。 -
性能影响:虽然使用
RequestAttributes很方便,但过度依赖可能导致代码难以维护。请合理组织代码结构,并遵循良好的编程实践。
通过理解和利用 RequestAttributes,你可以更灵活地管理 Web 应用程序中的状态信息,从而提高应用程序的可维护性和可扩展性。
为什么注解中的属性看起来它是方法,但是它设置值是通过看起来像属性一样的使用的?方法里面使用像是方法一样使用?
注解(Annotations)
注解是Java提供的一种对代码进行标记的机制,它不会直接影响代码的运行,但可以被编译器或运行时环境用来生成额外的信息或执行特定的处理。注解本身不包含逻辑代码,但它们可以携带元数据(即关于数据的数据),这些元数据可以被框架或工具用来生成代码、配置对象等。
属性(Attributes)与方法(Methods)的结合
在Java中,注解的属性通常看起来像是类的字段,但实际上它们是通过方法(通常是getter和setter方法的简化形式)来访问和修改的。这种设计有几个原因:
- 简洁性:允许开发者以类似属性的方式设置注解的值,使得代码更加简洁和直观。例如,@MyAnnotation(value = “example”)比使用完整的方法调用形式要简洁得多。
- 灵活性:虽然注解的属性看起来像字段,但它们实际上是通过方法访问的,这提供了更大的灵活性。例如,可以添加默认值、验证逻辑等。
- 一致性:Java的注解设计遵循了JavaBean的命名约定,即属性名后加()表示方法调用,这有助于保持Java语言的一致性。
示例
假设我们有一个自定义注解@MyAnnotation,它有一个名为value的属性:
public @interface MyAnnotation {
String value() default "default";
}
``
在使用这个注解时,我们可以像设置属性一样设置value:
```java
@MyAnnotation(value = "example")
public class MyClass {
// 类定义
}
但在注解的定义中,value()实际上是一个方法。当我们使用@MyAnnotation(value = “example”)时,编译器会自动将其转换为对value()方法的调用,并传递字符串"example"作为参数。
框架中的使用
在Spring等框架中,这种设计被广泛应用于配置和依赖注入。例如,@Autowired注解可以用来自动装配bean,而@Value注解可以用来注入配置值。这些注解背后的实现依赖于Java的反射机制来读取注解的元数据,并根据这些元数据执行相应的操作。
总之,注解中属性和方法的结合使用是为了提供一种简洁、灵活且一致的方式来定义和配置注解,同时利用Java的反射机制来实现复杂的运行时行为。
Spring SpEL(Spring Expression Language)
Spring SpEL(Spring Expression Language)是一个强大的表达式语言,允许在运行时查询和操作对象图。它支持各种功能,包括属性访问、方法调用、算术运算、逻辑运算等。
1. 基本语法
SpEL 表达式以 # 开头,用于引用变量;以 ${} 形式用于获取 Spring 容器中的值。
@Value("#{2 + 3}")
private int sum; // sum = 5
@Value("${my.property}")
private String myProperty; // 从配置文件中读取
2. 属性访问
可以通过 . 运算符访问对象的属性。
示例:
public class Person {
private String name;
private Address address;
// getters and setters
}
public class Address {
private String city;
// getters and setters
}
// 使用 SpEL 获取属性值
@Value("#{person.name}")
private String personName;
@Value("#{person.address.city}")
private String city;
3. 方法调用
可以调用对象的方法。
示例:
public class Calculator {
public int add(int a, int b) {
return a + b;
}
}
// 调用方法
@Value("#{calculator.add(10, 20)}")
private int result; // result = 30
4. 数组和集合操作
可以直接对数组和集合进行索引或使用集合函数。
示例:
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
// 获取第一个元素
@Value("#{names[0]}")
private String firstName; // firstName = "Alice"
// 获取列表大小
@Value("#{names.size()}")
private int size; // size = 3
5. 条件表达式
使用三元运算符实现条件判断。
示例:
boolean isAdult = true;
// 根据条件设置值
@Value("#{isAdult ? 'Adult' : 'Minor'}")
private String status; // status = "Adult"
6. 操作符
SpEL 支持多种操作符,如算术运算符、比较运算符和逻辑运算符。
示例:
int a = 10;
int b = 20;
// 加法运算
@Value("#{a + b}")
private int sum; // sum = 30
// 比较运算
@Value("#{a > b ? 'A is greater' : 'B is greater'}")
private String comparisonResult; // comparisonResult = "B is greater"
7. 正则表达式匹配
SpEL 支持正则表达式,可以用来进行字符串匹配。
示例:
String emailAddress = "test@example.com";
// 检查是否为有效邮箱格式
@Value("#{'${emailAddress}' matches '\\w+@(\\w+\\.)+(\\w+)' }")
private boolean isValidEmail; // isValidEmail 为 true 或 false 根据情况而定。
8. 自定义函数
你可以在 Spring 中注册自定义函数,并在 SpEL 中使用它们。
示例:
首先定义一个工具类:
@Component("mathUtils")
public class MathUtils {
public static double square(double number) {
return number * number;
}
}
然后在 SpEL 中使用这个方法:
// 调用自定义函数计算平方值
@Value("#{mathUtils.square(5)}")
private double squareOfFive; // squareOfFive = 25.0
总结
Spring SpEL 是一种灵活且功能丰富的表达式语言,能够帮助开发者轻松地进行动态数据处理。在实际应用中,它常用于配置注入、条件判断以及复杂业务逻辑的实现。通过结合 Java 对象及其方法,SpEL 可以极大提高代码的可读性与可维护性。
Advisor、PointcutAdvisor 和 IntroductionAdvisor
在 Spring AOP(面向切面编程)中,Advisor、PointcutAdvisor 和 IntroductionAdvisor 是实现横切关注点的核心概念。下面是对这三者的详细介绍:
1. Advisor
定义:
Advisor 是一个接口,它封装了一个增强(Advice)和应用这个增强的目标对象的选择逻辑。简单来说,Advisor 可以看作是将增强与其适用范围结合在一起的一种机制。
组成部分:
- Advice:实际执行的操作,如前置通知、后置通知等。
- Pointcut:定义哪些连接点(Join Point)会被 Advice 应用。
示例代码:
import org.aopalliance.intercept.MethodInterceptor;
import org.springframework.aop.Advisor;
import org.springframework.aop.Pointcut;
public class MyAdvisor implements Advisor {
private final MethodInterceptor advice; // 增强
private final Pointcut pointcut; // 切入点
public MyAdvisor(MethodInterceptor advice, Pointcut pointcut) {
this.advice = advice;
this.pointcut = pointcut;
}
@Override
public Advice getAdvice() {
return this.advice;
}
@Override
public Pointcut getPointcut() {
return this.pointcut;
}
}
2. PointcutAdvisor
定义:
PointcutAdvisor 是 Advisor 的子接口,它专注于根据切入点表达式来确定哪些方法需要应用给定的增强。
特点:
- 提供了一个
getPointcut()方法,用于获取具体的切入点。 - 通常用于配置基于方法名称或注解等条件的拦截器。
示例代码:
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class LoggingAspect implements PointcutAdvisor {
@Before("execution(* com.example.service.*.*(..))")
public void logBefore(JoinPoint joinPoint) {
System.out.println("Logging before method: " + joinPoint.getSignature().getName());
}
@Override
public Pointcut getPointcut() {
return new AspectJExpressionPointcut("execution(* com.example.service.*.*(..))");
}
@Override
public Advice getAdvice() {
return (MethodInterceptor) this::logBefore; // 使用 lambda 表达式作为增强逻辑
}
}
3. IntroductionAdvisor
定义:
IntroductionAdvisor 是另一种类型的 Advisor,它允许为现有类添加新的方法或属性,而无需修改原始类。这种方式通常用于引入新功能,比如实现某个接口而不影响原有类结构。
特点:
- 它可以通过动态代理为目标对象添加额外的方法或行为。
- 常用于提供跨多个类共享的新功能,例如日志记录、安全性等。
示例代码:
import org.springframework.aop.IntroductionInterceptor;
public class SecurityIntroduction implements IntroductionAdvisor {
@Override
public boolean implementsInterface(Class<?> intf) {
return intf == SecurityService.class; // 检查是否实现了指定接口
}
@Override
public Advice getAdvice() {
return new IntroductionInterceptor() {
@Override
public void secureMethod() {
System.out.println("Security check performed.");
}
};
}
}
总结
- Advisor 是 AOP 中最基本的概念,封装了增强和适用范围。
- PointcutAdvisor 是一种特定类型的 Advisor,根据切入点来决定何时应用增强。
- IntroductionAdvisor 允许在不修改目标对象代码的情况下,为其增加新的行为或属性,扩展其功能。
这些组件共同构成了 Spring AOP 的灵活性和强大能力,使得开发者能够轻松地实现横切关注点,提高代码复用性和可维护性。
4432

被折叠的 条评论
为什么被折叠?



