大家好,我是程序员强子。
又来刷英雄熟练度咯~今天专攻 Spring Bean 核心逻辑~
我们来看一下,今晚我们准备练习哪些内容:
Bean 的定义与注册:3 种定义方式,BeanDefinition 元数据,BeanDefinitionRegistry 注册器
依赖注入的实现:3 种注入方式及场景选型,@Autowired 匹配规则,底层逻辑
动态代理: JDK 动态代理(InvocationHandler)、CGLIB 动态代理(MethodInterceptor)核心原理
Bean 的作用域与线程安全:5 种作用域实战场景,单例 Bean 线程安全问题,ThreadLocal 应用,线程安全 3 种解决方案
Bean 的定义与注册
核心概念
BeanDefinition 是 IoC 容器中描述 Bean 的元数据接口
BeanDefinition 封装了 Bean 的所有配置信息
Spring 容器通过解析 BeanDefinition 来实例化、配置和管理 Bean
核心属性
所有 BeanDefinition 实现类都继承自抽象类 AbstractBeanDefinition,它定义了通用属性
常用的 BeanDefinition 子类
GenericBeanDefinition
Spring 推荐的默认实现,可替代传统的 RootBeanDefinition 和 ChildBeanDefinition
适合于 编程式注册 Bean(Java API 方式)、动态生成 BeanDefinition 等场景
// 创建 GenericBeanDefinitionGenericBeanDefinition userServiceDefinition = new GenericBeanDefinition();userServiceDefinition.setBeanClass(UserService.class); // 设置 Bean 类型userServiceDefinition.setScope(BeanDefinition.SCOPE_SINGLETON); // 作用域userServiceDefinition.setLazyInit(true); // 懒加载userServiceDefinition.getPropertyValues().add("userDao", new RuntimeBeanReference("userDao")); // 注入依赖
// 注册到容器DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();beanFactory.registerBeanDefinition("userService", userServiceDefinition);
复制代码
RootBeanDefinition & ChildBeanDefinition
RootBeanDefinition:无父 Bean 的 BeanDefinitionSpring 内部处理合并 BeanDefinition 时(如子 Bean 合并父 Bean 配置)会使用
ChildBeanDefinition: 必须依赖父 BeanDefinition,继承父的配置并可覆盖部分属性 Spring 3.0 后推荐用 GenericBeanDefinition + parentName 属性替代,灵活性更高
合并机制当 BeanDefinition 存在父子继承关系(如 ChildBeanDefinition 或 GenericBeanDefinition 指定 parentName),Spring 会在初始化 Bean 前将子 BeanDefinition 与父 BeanDefinition 合并,生成最终的 RootBeanDefinition
AnnotatedBeanDefinition
专门用于封装基于注解的 Bean 元数据(如 @Component、@Bean 注解的类),包含注解属性、方法元数据等
子实现 ScannedGenericBeanDefinition:组件扫描(@ComponentScan)时生成,对应 @Component/@Service/@Repository 等注解的类。AnnotatedGenericBeanDefinition:通过 @Bean 注解方法或 @Import 导入的类生成。
ConfigurationClassBeanDefinition
专门用于 @Configuration 类中的 @Bean 方法生成的 BeanDefinition,支持配置类的特殊处理(如 CGLIB 代理)
FactoryBeanDefinition
用于封装 FactoryBean 类型的 Bean 元数据
Spring 会先实例化 FactoryBean,再通过 getObject() 方法获取实际 Bean
那 FactoryBean 到底有什么作用呢?来,紧跟强子的脚步,我们详细剖析~
FactoryBean
首先,本身是一个 Bean~
Spring 不会直接把它当作你要的最终对象,而是会调用它的 生产方法-getObject, 拿到它造出来的真正对象
FactoryBean 到底解决什么问题?
主要用来处理对象创建比较复杂的场景
比如对象需要很多参数配置、创建步骤繁琐,或者需要根据不同条件动态生成对象
封装复杂对象的创建逻辑有些对象的创建像 搭乐高:要设置一堆参数、调用多个方法、甚至依赖其他组件创建数据库连接池(需要配置 URL、用户名、密码、最大连接数等一堆参数);创建 MyBatis 的 SqlSessionFactory(需要加载映射文件、配置数据源、设置插件等);创建 Redis 客户端(需要配置地址、密码、序列化方式等)
动态生成对象可以根据不同条件,让 FactoryBean 造不同的对象开发环境返回 测试数据源,生产环境返回 正式数据源;根据用户配置,返回不同的缓存实例(本地缓存 / Redis 缓存)
注册
XML 配置方式
使用标签,指定 id(Bean 名称)、class(全类名)
<!-- applicationContext.xml --><?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 注册 UserService Bean,指定名称为 userService --> <bean id="userService" class="com.example.service.UserService"/>
<!-- 非命名方式:省略 id,Spring 自动生成名称(全类名#0) --> <bean class="com.example.service.OrderService"/>
</beans>
复制代码
注解方式
组件扫描方式
在配置类添加 @ComponentScan 指定扫描包;
在类上添加下面这些注解,Spring 自动注册 Bean
@Component:通用组件注解
@Controller:MVC 控制器
@Service:业务逻辑层
@Repository:数据访问层
@Bean 注解
用于配置类中方法,方法返回值为 Bean 实例
Spring 注册该 Bean,默认名称为方法名
@Configurationpublic class AppConfig {
// 命名方式:注册 userDao Bean(名称为 userDao) @Bean public UserDao userDao() { return new UserDao(); }
// 非命名方式:自定义名称为 myUserService @Bean("myUserService") public UserService userService() { return new UserService(userDao()); // 注入 userDao }}
复制代码
高级注解:@Import
用于批量导入 Bean 或配置类
demo: 导入单个类
// 导入单个类(自动注册为 Bean)@Import(UserService.class)@Configurationpublic class AppConfig {}
复制代码
demo: 导入配置类
// 导入配置类@Import(AppConfig2.class)@Configurationpublic class AppConfig {}
复制代码
demo: 导入 ImportSelector
// 导入 ImportSelector(动态选择类)public class MyImportSelector implements ImportSelector { @Override public String[] selectImports(AnnotationMetadata metadata) { return new String[]{"com.example.service.OrderService"}; // 注册 OrderService }}
@Import(MyImportSelector.class)@Configurationpublic class AppConfig {}
复制代码
条件注册:@Conditional
根据条件动态注册 Bean
@Bean@Conditional(WindowsCondition.class) // 仅 Windows 系统注册public SystemService windowsSystemService() { return new WindowsSystemService();}
复制代码
Spring Boot 提供的条件注解(@ConditionalOnXXX), 非常好用,总结一下~
如何基于 Class 是否存在动态注册 Bean?
@ConditionalOnClass / @ConditionalOnMissingClass
当类路径中存在指定类 /不存在指定类时,才注册 Bean
// 仅当类路径中有 RedisTemplate 类(引入 spring-data-redis 依赖)时,注册 RedisService@Bean@ConditionalOnClass(RedisTemplate.class)public RedisService redisService() { return new RedisService();}
// 当类路径中没有 MongoTemplate 类时,注册本地缓存 Service@Bean@ConditionalOnMissingClass("org.springframework.data.mongodb.core.MongoTemplate")public LocalCacheService localCacheService() { return new LocalCacheService();}
复制代码
如何基于 Bean 是否存在动态注册 bean?
@ConditionalOnBean / @ConditionalOnMissingBean
当容器中存在/不存在 指定 Bean 时,才注册当前 Bean
// 当容器中有 DataSource Bean 时,注册事务管理器@Bean@ConditionalOnBean(DataSource.class)public PlatformTransactionManager transactionManager(DataSource dataSource) { return new DataSourceTransactionManager(dataSource);}
// 当容器中没有 UserService Bean 时,注册默认的 UserService@Bean@ConditionalOnMissingBean(UserService.class)public UserService defaultUserService() { return new DefaultUserService();}
复制代码
如何基于配置属性是否存在动态注册 Bean?
当配置文件(Properties/YAML)中存在指定属性且满足条件时,才注册 Bean
@ConditionalOnProperty
prefix:属性前缀(比如 service.user);
name:属性名(比如 enabled);
havingValue:属性需要匹配的值,默认只要属性存在即满足
matchIfMissing:属性不存在时是否匹配(默认 false)
配置文件:
# application.ymlservice: user: enabled: true
复制代码
代码 demo
// 仅当 service.user.enabled=true 时,注册 UserService@Bean@ConditionalOnProperty(prefix = "service.user", name = "enabled", havingValue = "true")public UserService userService() { return new UserService();}
// 若 service.order.enabled 未配置,默认注册 OrderService(matchIfMissing=true)@Bean@ConditionalOnProperty(prefix = "service.order", name = "enabled", matchIfMissing = true)public OrderService orderService() { return new OrderService();}
复制代码
如何基于资源是否存在动态注册 bean?
@ConditionalOnResource
当类路径中存在指定资源文件时,才注册 Bean
// 仅当类路径中有 config/user.properties 文件时,注册 UserConfigService@Bean@ConditionalOnResource(resources = "classpath:config/user.properties")public UserConfigService userConfigService() { return new UserConfigService();}
复制代码
如何基于表达式是否满足条件动态注册 bean?
@ConditionalOnExpression
// 当配置中 service.enabled=true 且环境是 dev 时,注册 DevService@Bean@ConditionalOnExpression("${service.enabled:true} && 'dev'.equals(${spring.profiles.active})")public DevService devService() { return new DevService();}
复制代码
如何自定义 @Conditional 注解 ?
如果需要复用某个条件逻辑,可以自定义组合注解(封装 @Conditional + 自定义 Condition)。
示例:自定义 “仅生产环境注册” 的注解
// 1. 自定义 Conditionpublic class ProdEnvCondition implements Condition { @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { return "prod".equals(context.getEnvironment().getProperty("spring.profiles.active")); }}
// 2. 自定义组合注解@Target({ElementType.TYPE, ElementType.METHOD})@Retention(RetentionPolicy.RUNTIME)@Conditional(ProdEnvCondition.class) // 绑定 Conditionpublic @interface ConditionalOnProdEnv {}
// 3. 使用自定义注解@Bean@ConditionalOnProdEnvpublic ProdMonitorService prodMonitorService() { return new ProdMonitorService();}
复制代码
Java API 方式
通过 Spring 底层 API 手动注册 Bean,适用于动态生成 Bean
BeanDefinitionRegistry:注册 BeanDefinition 的接口(如 DefaultListableBeanFactory);
GenericBeanDefinition:BeanDefinition 的通用实现
ApplicationContext.registerBean():简化的编程式注册
非命名方式
// 1. 创建 BeanFactoryDefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
// 2. 定义 BeanDefinition(指定类)GenericBeanDefinition userServiceDefinition = new GenericBeanDefinition();userServiceDefinition.setBeanClass(UserService.class);
// 3. 注册 Bean(非命名:Spring 自动生成名称)beanFactory.registerBeanDefinition(null, userServiceDefinition);
// 或使用 ApplicationContext 简化AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();context.registerBean(UserService.class); // 非命名注册context.refresh();
复制代码
命名方式(指定 Bean 名称)
// 方式1:通过 BeanDefinitionRegistryDefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();GenericBeanDefinition userDaoDefinition = new GenericBeanDefinition();userDaoDefinition.setBeanClass(UserDao.class);beanFactory.registerBeanDefinition("userDao", userDaoDefinition); // 指定名称 userDao
// 方式2:通过 ApplicationContextAnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();context.registerBean("myUserService", UserService.class); // 指定名称 myUserServicecontext.refresh();
// 获取 BeanUserService userService = context.getBean("myUserService", UserService.class);
复制代码
外部配置集成方式
通过外部配置(Properties/YAML/ 环境变量 / 配置中心)动态配置 Bean
@PropertySource 加载 Properties/YAML
配置文件 app.properties
# app.propertiesuser.name=testuser.age=20
复制代码
demo
@Configuration@PropertySource("classpath:app.properties") // 加载 Properties 文件public class AppConfig {
@Value("${user.name}") // 绑定配置值 private String userName;
@Bean public User user() { return new User(userName, Integer.parseInt("${user.age}")); }}
// YAML 加载示例(需自定义 PropertySourceFactory)@Configuration@PropertySource(value = "classpath:app.yaml", factory = YamlPropertySourceFactory.class)public class AppConfig {}
复制代码
环境变量 & 命令行参数
Spring 自动加载环境变量、命令行参数(优先级更高),通过 Environment 或 @Value 获取
@Autowiredprivate Environment environment;
public void test() { String env = environment.getProperty("ENV"); // 获取环境变量 ENV String cmdArg = environment.getProperty("user.id"); // 获取命令行参数 --user.id=100}
复制代码
拿到 了 BeanDefinition,然后呢?
我们平时写 CURD 的时候会写 Service 接口对吧,
那 BeanDefinitionRegistry 相当于 Service 接口了
最常用的实现类是 DefaultListableBeanFactory ,实现了 BeanDefinitionRegistry 接口,同时也显示了很多其他的接口~
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable { ...}
复制代码
demo
// 创建BeanFactory(容器)DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
// 构建BeanDefinitionBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(UserServiceImpl.class) .setScope("singleton") .addPropertyReference("userDao", "userDao") // 依赖userDao .getBeanDefinition();
// 注册BeanDefinitionbeanFactory.registerBeanDefinition("userService", beanDefinition);
// 获取BeanUserService userService = beanFactory.getBean(UserService.class);
复制代码
Spring 容器启动时,不管是解析 XML、扫描注解还是处理 @Bean,最终都是调用 BeanDefinitionRegistry 的注册方法,把 BeanDefinition 存到容器里
依赖注入
Spring 自动帮你把 Bean 的依赖 塞进去,不用手动 new。
那问题就来了,这两步很关键~
怎么注入: 对应注入方式, 场景不同,选型不同
注入什么 & 怎么找依赖 : 对应着怎么查找依赖
注入方式
构造器注入
通过构造方法注入,确保 Bean 创建时依赖必存在,解决 NullPointerException 问题
@Servicepublic class UserServiceImpl implements UserService { private final UserDao userDao; // 不可变,线程安全 // 构造器注入(Spring 4.3+可省略@Autowired) public UserServiceImpl(UserDao userDao) { this.userDao = userDao; }}
复制代码
构造器注入的成员变量可以不加 final,但推荐加 final
同时, 可以加上 @RequiredArgsConstructor 注解,这样就可以不用手动写构造器了
Setter 注入
通过 setter 方法注入
@Servicepublic class UserServiceImpl implements UserService { private UserDao userDao; @Autowired // 可选:没有userDao也能创建Bean public void setUserDao(UserDao userDao) { this.userDao = userDao; }}
复制代码
字段注入
直接在字段上用 @Autowired,代码最简洁,但缺点明显
@Servicepublic class UserServiceImpl implements UserService { @Autowired // 字段注入 private UserDao userDao;}
复制代码
自动注入的匹配规则
byType:先按类型找(比如找所有 UserDao 类型的 Bean);
byName:如果类型匹配到多个(比如有 userDaoImpl1 和 userDaoImpl2),就按字段名 / 参数名匹配 Bean 名称;
@Qualifier:如果 byName 也匹配不到,就用 @Qualifier("指定 Bean 名称")精准定位。
@Repository("userDaoImpl1")public class UserDaoImpl1 implements UserDao {}
@Repository("userDaoImpl2")public class UserDaoImpl2 implements UserDao {}
@Servicepublic class UserServiceImpl { // 用@Qualifier指定注入userDaoImpl1 @Autowired @Qualifier("userDaoImpl1") private UserDao userDao;}
复制代码
底层原理
由 AutowiredAnnotationBeanPostProcessor(Bean 后置处理器)实现的
它在 Bean 初始化前的 populateBean 阶段
延时注入
ObjectFactory
ObjectFactory 核心作用是延迟获取 Bean 实例
避免在依赖注入阶段立即初始化目标 Bean
适用于需要按需创建 Bean 或解决循环依赖的场景
核心特性是什么?
仅包含 getObject() 方法,每次调用都会触发 Bean 的获取
注入的是 ObjectFactory 容器,而非目标 Bean 本身,只有调用 getObject()时才会实际获取 / 初始化目标 Bean
Spring 内部也通过 ObjectFactory 处理单例 Bean 的循环依赖
@Componentpublic class ServiceA { // 注入ObjectFactory延迟获取ServiceB @Autowired private ObjectFactory<ServiceB> serviceBFactory;
public void doSomething() { // 调用getObject()时才初始化/获取ServiceB ServiceB serviceB = serviceBFactory.getObject(); serviceB.execute(); }}
@Componentpublic class ServiceB {}
复制代码
ObjectProvider
ObjectProvider 是 Spring 4.3 + 引入的接口,继承自 ObjectFactory
扩展了更灵活的延迟注入能力,是 Spring 官方推荐的替代 ObjectFactory 的方案
核心增强特性
容错能力:提供 getIfAvailable(),Bean 不存在时返回 null,避免 NPEgetIfUnique(),多个候选 Bean 时抛异常,否则返回...
多 Bean 处理:支持 stream()遍历所有候选 Bean(如同一接口的多个实现类);
自定义回调:ifAvailable(Consumer)(Bean 存在时执行回调)getIfAvailable(Supplier)(Bean 不存在时返回默认值)
兼容 ObjectFactory:保留 getObject()方法,无缝替换
@Componentpublic class ServiceA { // 注入ObjectProvider延迟获取ServiceB @Autowired private ObjectProvider<ServiceB> serviceBProvider;
public void doSomething() { // 容错获取:ServiceB不存在时返回null ServiceB serviceB = serviceBProvider.getIfAvailable(); if (serviceB != null) { serviceB.execute(); }
// 遍历同一接口的所有实现类(如ServiceB有多个子类) serviceBProvider.stream().forEach(ServiceB::execute);
// 无Bean时返回默认实例 ServiceB defaultServiceB = serviceBProvider.getIfAvailable(() -> new ServiceB()); }}
复制代码
@Lazy
用于标记 Bean 延迟初始化,或延迟注入依赖
核心作用是优化容器启动速度、解决循环依赖
延时初始化 demo
// ServiceB延迟初始化,容器启动时不创建@Component@Lazypublic class ServiceB {}
@Componentpublic class ServiceA { @Autowired private ServiceB serviceB; // 容器启动时,ServiceB未初始化,第一次调用serviceB时才创建}
复制代码
解决循环依赖 demo
@Component// 未标记@Lazy,默认立即初始化public class ServiceB {} // 未标记@Lazy,默认立即初始化
@Componentpublic class ServiceA { // 注入点标记@Lazy,serviceB是代理对象,第一次调用时才获取真实ServiceB @Autowired @Lazy private ServiceB serviceB;}
复制代码
原理
动态代理到底是怎么回事?接下来跟着强子仔细探寻一下答案~
动态代理
JDK 动态代理
基于 InvocationHandler
核心原理
代理类生成:通过 Proxy.newProxyInstance() 动态生成字节码(类名形如 $Proxy0),代理类内部会将所有接口方法调用转发给 InvocationHandler 的 invoke 方法
接口依赖: 目标类必须实现接口,JDK 动态代理生成的代理类($Proxy0)会继承 Proxy 类 + 实现目标接口
回调入口 InvocationHandler 的 invoke 方法是增强逻辑的核心入口,调用目标方法时会触发该方法,可在其中嵌入前置 / 后置增强逻辑,最终通过反射调用目标对象的方法
demo 如下
目标接口 + 实现类
// 1. 目标接口(必须)interface OrderService { void createOrder(String orderNo);}
// 2. 目标类(实现接口)class OrderServiceImpl implements OrderService { @Override public void createOrder(String orderNo) { System.out.println("目标类执行:创建订单【" + orderNo + "】"); }}
复制代码
InvocationHandler 自定义类
// 自定义 InvocationHandler(增强逻辑)class LogInvocationHandler implements InvocationHandler { private Object target; // 目标对象
public LogInvocationHandler(Object target) { this.target = target; }
/** * 代理方法调用时触发的回调方法 * @param proxy 代理对象本身(避免直接调用,防止递归) * @param method 被调用的目标方法 * @param args 方法参数 */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 前置增强:日志记录 System.out.println("JDK 代理前置:调用方法【" + method.getName() + "】,参数:" + args[0]); // 反射调用目标方法 Object result = method.invoke(target, args); // 后置增强:结果处理 System.out.println("JDK 代理后置:方法【" + method.getName() + "】执行完成"); return result; }}
复制代码
测试类
// 测试类public class JdkProxyDemo { public static void main(String[] args) { // 创建目标对象 OrderService target = new OrderServiceImpl(); // 创建 InvocationHandler(关联目标对象) InvocationHandler handler = new LogInvocationHandler(target); // 生成代理对象(核心:Proxy.newProxyInstance) OrderService proxy = (OrderService) Proxy.newProxyInstance( target.getClass().getClassLoader(), // 类加载器 target.getClass().getInterfaces(), // 目标接口数组 handler // 回调处理器 ); // 调用代理方法(触发 invoke 回调) proxy.createOrder("ORDER_20250520"); }}
复制代码
执行结果:
JDK 代理前置:调用方法【createOrder】,参数:ORDER_20250520目标类执行:创建订单【ORDER_20250520】JDK 代理后置:方法【createOrder】执行完成
复制代码
CGLIB 动态代理
基于 MethodInterceptor
核心原理
继承依赖:无需目标类实现接口,CGLIB 通过 ASM 框架动态生成目标类的子类作为代理类目标类 / 方法不能是 final,否则无法继承 / 重写
代理类生成:Enhancer 类指定父类(目标类)和回调接口 MethodInterceptor,生成的代理类名形如 目标类 XXX
回调入口:MethodInterceptor 的 intercept 方法是增强逻辑入口,调用代理方法时触发通过 methodProxy.invokeSuper(obj, args) 调用父类(目标类)的方法
Demo
目标类
// 目标类(无需实现接口)class UserService { public void updateUser(String username) { System.out.println("目标类执行:更新用户【" + username + "】"); }}
复制代码
自定义 MethodInterceptor
// 自定义 MethodInterceptor(增强逻辑)class CglibLogInterceptor implements MethodInterceptor { /** * 代理方法调用时触发的回调方法 * @param obj 代理对象(目标类的子类实例) * @param method 被调用的目标方法 * @param args 方法参数 * @param methodProxy 方法代理对象(用于调用父类方法) */ @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { // 前置增强:权限校验 System.out.println("CGLIB 代理前置:调用方法【" + method.getName() + "】,参数:" + args[0]); // 调用父类(目标类)的方法(非反射,效率更高) Object result = methodProxy.invokeSuper(obj, args); // 后置增强:日志记录 System.out.println("CGLIB 代理后置:方法【" + method.getName() + "】执行完成"); return result; }}
复制代码
测试类
// 测试类public class CglibProxyDemo { public static void main(String[] args) { // 创建 Enhancer(CGLIB 核心类,用于生成代理类) Enhancer enhancer = new Enhancer(); // 设置父类(目标类) enhancer.setSuperclass(UserService.class); // 设置回调处理器(MethodInterceptor) enhancer.setCallback(new CglibLogInterceptor()); // 生成代理对象(目标类的子类) UserService proxy = (UserService) enhancer.create(); // 调用代理方法(触发 intercept 回调) proxy.updateUser("张三"); }}
复制代码
执行结果
CGLIB 代理前置:调用方法【updateUser】,参数:张三目标类执行:更新用户【张三】CGLIB 代理后置:方法【updateUser】执行完成
复制代码
Bean 作用域
Spring 定义了 5 种 Bean 作用域,本质是控制 Bean 的 存活时间和 复用范围
单例 Bean 的线程安全问题:
解决方案 1
可以用 ThreadLocal 隔离线程状态
比如 Spring 的 RequestContextHolder,用 ThreadLocal 存储请求上下文
方案 2
用 prototype 作用域:每次请求新建实例,避免共享状态;
方案 3
同步锁 / 不可变对象:对可变状态加锁(性能差),或用不可变对象
总结
今天把 Spring 的底层地基给学扎实了!
本文聚焦 Spring 四大核心实战内容:
Bean 的 3 种定义方式及 BeanDefinition 元数据、BeanDefinitionRegistry 注册器的底层逻辑;
构造器 /setter/ 字段 3 种依赖注入方式的场景选型,以及 @Autowired 的匹配规则与底层实现;
JDK 动态代理(InvocationHandler)和 CGLIB 动态代理(MethodInterceptor)的核心原理;
是 Bean 的 5 种作用域实战,以及单例 Bean 线程安全问题与 3 种解决办法(无状态设计、同步锁、ThreadLocal)
帮 我们 吃透 Spring 底层,从会用到懂原理~~
熟练度刷不停,知识点吃透稳,下期接着练~
评论