Spring Core是Spring框架的基础API核心模块,提供了基本的IoC(Inversion of Control,控制反转)和DI(Dependency Injection,依赖注入)功能。
FileSystemResource是Spring框架中的一个实现了Resource接口的类,用于从文件系统中加载资源。它可以根据指定的文件路径来加载文件系统中的资源。
当你使用FileSystemResource加载资源时,你需要提供一个文件路径,它指向文件系统中的实际文件。FileSystemResource将会根据提供的路径去访问文件系统并加载相应的资源。
Spring Core提供了一个容器,也称为应用上下文(Application Context),它负责管理和装配应用程序中的对象。它实现了控制反转(IoC),即框架负责创建和管理对象的生命周期,而不是由开发人员手动创建和管理。同时还通过依赖注入管理对象间的依赖关系。对应的接口为:BeanFactory。
BeanFactory通过Autowired实现依赖注入,AutowiredAnnotationBeanPostProcessor是@Autowire注解的实现类,它是一个后置处理器,用于在Bean实例化后对标记了@Autowired注解的字段、构造函数或方法进行依赖注入。它会扫描Bean中的@Autowired注解,解析注解所标记的依赖关系,并将相应的依赖对象注入到对应的位置。processInjection()方法是在Spring框架中用于执行依赖注入的方法。
//缓存已检查过的成员变量
private final Set<String> lookupMethodsChecked = Collections.newSetFromMap(new ConcurrentHashMap<>(256));
//缓存类的候选构造函数
private final Map<Class<?>, Constructor<?>[]> candidateConstructorsCache = new ConcurrentHashMap<>(256);
//缓存类的依赖注入元数据
private final Map<String, InjectionMetadata> injectionMetadataCache = new ConcurrentHashMap<>(256);
public void processInjection(Object bean) throws BeanCreationException {
Class<?> clazz = bean.getClass();
//查找Bean中的包含@Autowire注解的字段、构造方法、方法
InjectionMetadata metadata = findAutowiringMetadata(clazz.getName(), clazz, null);
try {
metadata.inject(bean, null, null);
}
catch (BeanCreationException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanCreationException(
"Injection of autowired dependencies failed for class [" + clazz + "]", ex);
}
}
//遍历方法实现
private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {
// Fall back to class name as cache key, for backwards compatibility with custom callers.
String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
// Quick check on the concurrent map first, with minimal locking.
InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
synchronized (this.injectionMetadataCache) {
metadata = this.injectionMetadataCache.get(cacheKey);
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
if (metadata != null) {
metadata.clear(pvs);
}
metadata = buildAutowiringMetadata(clazz);
this.injectionMetadataCache.put(cacheKey, metadata);
}
}
}
return metadata;
}
BeanFactory定义了依赖查找的方法。依赖查找是一种主动获取依赖对象的方式,用于获取其他Bean或依赖的实例。通过依赖查找,可以在需要的时候动态的获取所需的依赖对象,并在代码中使用。
面向切面编程(Aspect-Oriented Programming)是一种编程范式,旨在通过将横切关注点与主要业务逻辑分离,提供一种更好的代码组织和模块化的方式。
AOP的思想是将这些横切关注点从主要业务逻辑中抽离出来,形成一个独立的模块,称为切面。切面可以定义通过预定义的方式或者在运行时动态的与主业务逻辑进行织入,从而实现对横切关注点的统一处理。
AOP可以将横切关注点从主要业务逻辑中分离出来,使主要业务逻辑更加清晰明了。
AOP可以消除重复的代码。通过使用AOP注解或配置,可以将需要切入的代码逻辑集中到切面中,从而避免在每个地方重复编写相同的代码。当切面需要修改时,只需修改一处逻辑,即可实现全局的变更。
AOP可以降低代码的复杂性。通过将横切关注点与主要业务逻辑分离,使得主要业务逻辑更加专注和清晰,减少了代码的混杂程度,提高了代码的可读性和可维护性。
下面是一个简单的例子,说明 AOP 如何解决日志记录的问题:
假设我们有一个类 UserService,其中包含了一些用户管理的方法,如 createUser()、deleteUser() 等。我们希望在每个方法执行前后记录日志。
public class UserService {
public void createUser(User user) {
Logger.log("Creating user: " + user.getName());
// 执行创建用户的逻辑
Logger.log("User created: " + user.getName());
}
public void deleteUser(String userId) {
Logger.log("Deleting user: " + userId);
// 执行删除用户的逻辑
Logger.log("User deleted: " + userId);
}
}
public aspect LoggingAspect {
before(): execution(public void UserService.*(..)) {
Logger.log("Method execution started: " + thisJoinPoint.getSignature().getName());
}
after(): execution(public void UserService.*(..)) {
Logger.log("Method execution completed: " + thisJoinPoint.getSignature().getName());
}
}
public class UserService {
public void createUser(User user) {
// 执行创建用户的逻辑
}
public void deleteUser(String userId) {
// 执行删除用户的逻辑
}
}
事件驱动、注解驱动、模块驱动等。
private final Set<Integer> registriesPostProcessed = new HashSet<>();
private final Set<Integer> factoriesPostProcessed = new HashSet<>();
/**
* Prepare the Configuration classes for servicing bean requests at runtime
* by replacing them with CGLIB-enhanced subclasses.
*/
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
int factoryId = System.identityHashCode(beanFactory);
if (this.factoriesPostProcessed.contains(factoryId)) {
throw new IllegalStateException(
"postProcessBeanFactory already called on this post-processor against " + beanFactory);
}
this.factoriesPostProcessed.add(factoryId);
if (!this.registriesPostProcessed.contains(factoryId)) {
// BeanDefinitionRegistryPostProcessor hook apparently not supported...
// Simply call processConfigurationClasses lazily at this point then.
processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory);
}
enhanceConfigurationClasses(beanFactory);
beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
}
入参:BeanDefinitionRegistry接口定义了对Bean定义的注册和管理操作,用于注册、存储、管理Bean定义。
Spring表达式语言模块。
public class SpelTest {
public static void main(String[] args) {
SpelExpressionParser parser = new SpelExpressionParser();
Expression exp = parser.parseExpression("'xxx'.concat('yyy')");
String value = (String) exp.getValue();
System.out.println(value);
exp = parser.parseExpression("'xxx'.bytes");
byte[] bytes = (byte[]) exp.getValue();
exp = parser.parseExpression("'xxx'.bytes.length");
Object expValue = exp.getValue();
System.out.println("length: " + expValue);
UserDto userDto = new UserDto();
userDto.setUserName("test");
userDto.setRoleNameZh("admin");
userDto.setId(1);
UserDto userDto2 = new UserDto();
userDto2.setUserName(userDto.getUserName());
//定义解析器
ExpressionParser expressionParser = new SpelExpressionParser();
//制定表达式
Expression expression = expressionParser.parseExpression("userName");
// 2 使用解析器解析表达式,获取对象的属性值
String name = (String) expression.getValue(userDto2);
//获取解析结果
System.out.println(name);
//使用解析器解析表达式,获取对象的属性值并进行运算
Expression exp2 = expressionParser.parseExpression("userName == 'xxx'");
// 3.1 获取解析结果
boolean result = exp2.getValue(userDto2, Boolean.class);
System.out.println(result);//true
}
}