Spring 简介

在线快速搭建SpringBoot项目

概述

  • Spring 诞生于 2003 年,是对早期 J2EE 规范复杂性的响应,使创建 Java 企业应用程序变得非常简单
  • 除了Java语言,还支持 Groovy 和 Kotlin 作为 JVM 上开发的替代语言
  • Spring Framework 6.0 开始, Spring 需要 Java 17+ 的支持

核心技术

  • Spring 框架的核心是容器模块,主要是【依赖注入】
  • Spring 框架延伸出的其它框架,如Spring MVC,Spring Boot,Spring Cloud等等

1、容器【​​IoC & DI】

  • 容器是Spring的核心,将原本由开发者创建Bean的工作交由容器来完成,通过容器来实现Bean管理
  • BeanFactory接口Ioc容器相关功能的顶级接口,默认Bean是延迟加载机制
  • ApplicationContext接口继承BeanFactory接口,默认Bean是实时加载,扩展了企业级功能(国际化、电子邮件、事件传播等等)

2、AOP

  • OOP( 面向对象编程)是通过调用方法来实现某些功能,无需关注方法实现细节
  • AOP是对OOP的补充,不更改原有代码的基础上对代码功能进行增强
  • 场景应用场景:记录请求和响应的日志、声明式事务@Transactional
  • 配置案例:
通过@Aspect注解开启AOP功能
通过@Pointcut注解定义切点
通过通知类型来实现具体的业务逻辑
环绕通知(@Around)(前置和后置):在方法调用之前和之后,执行通知
前置通知(@Before):方法执行之前,执行通知
返回通知(@AfterReturning):方法执行成功之后,执行通知
异常通知(@AfterThrowing):方法执行异常之后,执行通知
后置通知(@After):方法执行之后,不考虑其结果,执行通知
  • 使用环绕通知注意事项:
目标方法发生异常时,会触发执行异常通知和全局异常捕获,此时【返回通知】和【环绕通知-后置】不再执行
调用目标方法时用try-catch捕获了异常,但没有重新抛出,则事务切面无法感知异常,误认为方法执行成功,从而提交事务

3、声明式事务【@Transactional】

  • 基于AOP面向切面,它将具体业务与事务处理部分解耦,所以在实际开发中声明式事务用的比较多

  • 基于@Transactional注解(作用在接口、类、类方法)的声明式事务

  • 隔离等级(4)
    READ_UNCOMMITTED:允许另外一个事务可以看到这个事务未提交的数据
    READ_COMMITTED:保证一个事物提交后才能被另外一个事务读取
    REPEATABLE_READ:防止脏读,不可重复读
    SERIALIZABLE:串化读

  • 传播行为(7)
    PROPAGATION_required(默认):当前存在事务则加入该事务,否则创建一个新的事务
    PROPAGATION_nested:当前存在事务则创建一个事务作为当前事务的嵌套事务来运行
    否则等价于默认传播行为
    PROPAGATION_supports:当前存在事务则加入该事,否则以非事务继续运行
    PROPAGATION_mandatory:当前存在事务则加入该事务,否则抛出异常
    PROPAGATION_requires_new:当前存在事务则挂起,然后创建一个新的事务
    PROPAGATION_not_supported:当前存在事务则挂起,然后以非事务继续运行
    PROPAGATION_never:当前存在事务则抛出异常,然后以非事务方式运行

  • 失效场景
    @Transactional修饰的方法必须为public,否则事务不会生效
    发生的异常被捕获了,则事务不会生效
    如果updateA被@Transactional修饰,即使updateB没有,因为updateB是在updateA中调用,所有这两个方法都在同一个事物中

4、事件传播(观察者模式)

场景案例:订单入库成功后,需要发送短信通知用户。一般情况都会把短信通知加在订单入库的后边,这样做违反了单一职责(订单保存功能里变不应该杂糅消息通知功能),如果后期需要添加微信消息通知功能,则需要在原有的基础上进行额外添加,这样做又违反了开闭原则(对拓展开放,对修改关闭)。优化方案:通过观察者模式使创建订单和消息通知功能进行分离

@Controller
@RequestMapping("test")
public class TestController {
    @Resource
    private ApplicationContext applicationContext;

    @GetMapping("event")
    @ResponseBody
    public Object event() throws Exception {
        // TODO 创建事件
        OrderSaveEvent orderSaveEvent = new OrderSaveEvent(this,"000000","创建成功");
        // TODO 发布事件
        applicationContext.publishEvent(orderSaveEvent);
        return ResponseUtil.success();
    }
}
  • 自定义订单保存成功事件
public class OrderSaveEvent extends ApplicationEvent {
    private String orderNum;
    public String getOrderNum() { return orderNum; }
    public void setOrderNum(String orderNum) { this.orderNum = orderNum; }

    private String desc;
    public String getDesc() { return desc; }
    public void setDesc(String desc) { this.desc = desc; }

    public OrderSaveEvent(Object source, String orderNum, String desc) {
        super(source);
        this.desc = desc;
        this.orderNum = orderNum;
    }
}
  • 短信通知监听器(接口、无序)
@Component
@Async("asyncTaskExecutor")
public class OrderSmsListener implements ApplicationListener<OrderSaveEvent> {
    @Override
    public void onApplicationEvent(OrderSaveEvent event) {
        LoggerUtil.info(MessageFormat.format("短信提示:订单【{0}】{1}",event.getOrderNum(),event.getDesc()));
    }
}
  • 微信通知监听器(注解、无序)
@Component
@Async("asyncTaskExecutor")
public class OrderSmsListener {
    @EventListener
    public void sms(OrderSaveEvent event) {
        LoggerUtil.info(MessageFormat.format("微信提示:订单【{0}】{1}",event.getOrderNum(),event.getDesc()));
    }
}

自定义Bean

FactoryBean

@Component
public class DemoFactoryBean implements FactoryBean<Demo> {
    // 该方法返回该 FactoryBean 生产的对象。我们需要实现该方法以给出自己对象实例化逻辑
    @Override
    public Demo getObject() throws Exception {
        Demo demo = new Demo();
        demo.setDesc("DemoFactoryBean");
        return demo;
    }
    // 返回 FactoryBean 生产的对象类型。如果预先无法确定,则返回null
    @Override
    public Class<?> getObjectType() {  return Demo.class; }
    // FactoryBean 生产的对象是否要以singleton(单例)形式存于容器中
    @Override
    public boolean isSingleton() { return true; }
}
@Controller
@RequestMapping("demo")
public class DemoController {
	@Resource
    private DemoFactoryBean demoFactoryBean;
}

@Configuration和@Bean

@Configuration
public class Demo{
    public Demo() {
        System.out.println("第1步:容器初始化");
    }
    @Bean(value = "demo", initMethod = "myInit", destroyMethod = "myDestroy")
    // singleton 首次创建,多次从缓存中取
    // prototype每调用一次创建一个新的实例
    // request 每一个请求创建一个新的实例
    // session 同一个session共享同一个实例
    @Scope("singleton")
    public Demo getDemo() {
        System.out.println("第1.1步:初始化容器中的bean");
        Demo demo = new Demo();
        demo.setDesc("测试Bean的生命周期");
        return demo;
    }
}

Bean生命周期

第一步:实例化(空属性)对象

  • 根据【XML、注解或JavaConfig】配置获取BeanDefinition对象,该对象中定义了Bean的各种属性:
lazyInit:是否延迟加载、dependencies:依赖Bean、scope:Bean作用域
className:Bean类名、propertyValues:Bean属性值
constructorArgumentValues:构造函数参数值、initMethodName:初始化方法名、destroyMethodName:销毁方法名
  • ​​确认创建方式​​:构造函数或工厂方法
  • 创建​​:创建属性为空的对象

构造函数初始化与循环依赖问题

  • 构造函数的调用发生在实例化阶段,若构造函数中声明了依赖参数,则容器会在实例化当前bean之前,尝试先创建其依赖bean
  • A依赖B(A的构造函数/属性需要B的实例),B依赖A(B的构造函数/属性需要A的实例),此时就会出现循环依赖的问题
  • Spring无法解决构造函数注入的循环依赖问题,如果出现会直接报异常
构造函数参数上添加@Lazy注解,延迟依赖bean的实例化(创建代理对象暂时替代)
因为setter依赖注入发生在 “实例化之后”,所以可以改用setter方式注入依赖

第二步:属性注入

  • 该阶段是「依赖注入」的核心环节,就像给刚建好的毛坯房(实例化后的空对象)安装水电家具
(@Value)加载yml配置参数
(@Autowired)按类型注入其它Bean
(@Resource)按名称注入其它Bean
(@Inject)通常用在类的构造函数、方法或字段上,表示这些地方需要依赖注入

第三步:初始化

  • 根据具体业务场景,可以在初始化之前【postProcessBeforeInitialization之前】和实例化之后依次实现BeanNameAware→BeanFactoryAware→ApplicationContextAware接口,作用是允许Bean与Spring容器进行交互,获取容器级别的资源或元数据
1. BeanNameAware:
容器会先调用 BeanNameAware 接口的 setBeanName() 方法,将当前bean的id传递给bean实例
2. BeanFactoryAware:
容器会调用 BeanFactoryAware 接口的 setBeanFactory() 方法,将当前bean所在的BeanFactory实例传递给bean
3. ApplicationContextAware:
容器会调用 setApplicationContext() 方法,将当前bean所在的 ApplicationContext 实例传递给bean
  • 该阶段是生命周期中的关键环节,Bean已完成实例化和属性注入,即将投入正式使用,以下是「精装修」阶段的完整流程解析:
- 实现BeanPostProcessor接口,重写postProcessBeforeInitialization(前置)和postProcessAfterInitialization(后置)方法
- 自定义@PostConstruct注解的方法,在属性注入完成后执行。符合注解驱动的开发方式,且不依赖于Spring接口(减少侵入性)
- 实现InitializingBean接口,重写afterPropertiesSet方法,在@PostConstruct之后执行,依赖于Spring接口(侵入性)

第四步:销毁

  • 自定义@PreDestroy注解的方法,执行销毁前的逻辑
  • 实现DisposableBean接口,重写destroy方法,执行销毁

案例

  • CustomBeanPostProcesser
@Slf4j
@Component
public class CustomBeanPostProcesser implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        // beanName: lifecycleBean
        // beanFullName: com.jh.LifecycleBean
        String beanFullName = bean.getClass().getName();
        if (bean instanceof LifecycleBean) { //
            log.error("{}: LifecycleBean BeanPostProcessor: postProcessBeforeInitialization - {}", DateUtil.dateToDateTimeCharacter(new Date()), beanName);
        }
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        // beanName: lifecycleBean
        // beanFullName: com.jh.LifecycleBean
        String beanFullName = bean.getClass().getName();
        if (bean instanceof LifecycleBean) {
            log.error("{}: LifecycleBean BeanPostProcessor: postProcessAfterInitialization - {}", DateUtil.dateToDateTimeCharacter(new Date()), beanName);
        }
        return bean;
    }
}
  • LifecycleBean
@Slf4j
@Component
public class LifecycleBean implements 
BeanNameAware, BeanFactoryAware, ApplicationContextAware, InitializingBean, DisposableBean {
    public LifecycleBean() {
        log.error("{}: LifecycleBean 构造函数", DateUtil.dateToDateTimeCharacter(new Date()));
    }

    public void customInit() {
        log.error("{}: LifecycleBean 自定义init方法", DateUtil.dateToDateTimeCharacter(new Date()));
    }

    public void customDestroy() {
        log.error("{}: LifecycleBean 自定义destroy方法", DateUtil.dateToDateTimeCharacter(new Date()));
    }

    @Override
    public void setBeanName(String beanName) {
        log.error("{}: LifecycleBean BeanNameAware接口返回的实例ID: {}", DateUtil.dateToDateTimeCharacter(new Date()), beanName);
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) {
        log.error("{}: LifecycleBean BeanFactoryAware接口返回的BeanFactory对象", DateUtil.dateToDateTimeCharacter(new Date()));
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) {
        log.error("{}: LifecycleBean ApplicationContextAware的ApplicationContext对象", DateUtil.dateToDateTimeCharacter(new Date()));
    }

    @PostConstruct
    public void postConstruct() {
        log.error("{}: LifecycleBean @PostConstruct【推荐】", DateUtil.dateToDateTimeCharacter(new Date()));
    }

    @Override
    public void afterPropertiesSet() {
        log.error("{}: LifecycleBean InitializingBean接口afterPropertiesSet【不推荐】", DateUtil.dateToDateTimeCharacter(new Date()));
    }

    @PreDestroy
    public void preDestroy() {
        log.error("{}: LifecycleBean 即将被销毁", DateUtil.dateToDateTimeCharacter(new Date()));
    }

    @Override
    public void destroy() {
        log.error("{}: LifecycleBean 销毁成功", DateUtil.dateToDateTimeCharacter(new Date()));
    }
}
  • LifecycleBeanConfig
@Configuration
public class LifecycleBeanConfig {
    @Bean(initMethod = "customInit", destroyMethod = "customDestroy")
    @Scope("singleton")
    public LifecycleBean lifecycleBean() {
        return new LifecycleBean();
    }
}
  • 执行日志
2025-08-14 18:48:15: LifecycleBean 构造函数

2025-08-14 18:48:15: LifecycleBean BeanNameAware接口返回的实例ID: lifecycleBean
2025-08-14 18:48:15: LifecycleBean BeanFactoryAware接口返回的BeanFactory对象
2025-08-14 18:48:15: LifecycleBean ApplicationContextAware的ApplicationContext对象

2025-08-14 18:48:15: LifecycleBean BeanPostProcessor: postProcessBeforeInitialization - lifecycleBean
2025-08-14 18:48:15: LifecycleBean @PostConstruct【推荐】
2025-08-14 18:48:15: LifecycleBean InitializingBean接口afterPropertiesSet【不推荐】
2025-08-14 18:48:15: LifecycleBean 自定义init方法
2025-08-14 18:48:15: LifecycleBean BeanPostProcessor: postProcessAfterInitialization - lifecycleBean

2025-08-14 18:48:22: LifecycleBean 即将被销毁
2025-08-14 18:48:22: LifecycleBean 销毁成功
2025-08-14 18:48:22: LifecycleBean 自定义destroy方法

SpringMVC【已过时,基本不用了】

SpringMvc是Spring的一部分,基于JAVA实现MVC的WEB框架,其核心就是通过前端控制器(DispatcherServlet)将请求分发到不同的控制器(早期通过继承HttpServlet类实现该功能,Spring2.5开始通过@Controller实现)

  • 启动原理
    应用启动时会读取(webapp/WEB-INF/web.xml)文件来加载Spring容器(applicationContext.xml)和Servlet容器(dispatcher-servlet.xml)

  • applicationContext.xml(Spring容器)
    扫描相关类并纳入IOC容器(@Component、@Service、@Repository等等)
    配置数据库连接池和事务
    自定义Bean

  • dispatcher-servlet.xml(Servlet容器)
    扫描相关类并纳入IOC容器(@RestController、@Controller)
    配置静态资源解析器、视图解析器、文件上传解析器
    配置拦截器

SpringBoot

  • 内置多种Web容器(默认Tomcat),通过jar模式可以直接启动并运行
  • 内置监控模块,可以对系统运行情况进行监控
  • 支持众多starter依赖项(引入相关starter依赖项即可根据SpringBoot主版本号自动加载与之对应的Jar包)
  • 支持自动装配功能,实现开箱即用

复合注解【@SpringBootApplication】

  • @ComponentScan【组件扫描】扫描启动类同级目录(及子目录)下符合条件的类并纳入容器管理
  • @Configuration表示该类是一个配置类​​,通常与@Bean注解配合使用,用于自定义Bean并纳入容器管理
  • @EnableAutoConfiguration【自动配置】,Spring Boot启动时​​会扫描所有依赖JAR中的配置清单文件,将符合条件的配置类​​纳入容器管理,最终实现 ​​“开箱即用”的效果

自动装配【spring-boot-autoconfigure-x.x.x.jar】

  • Spring Boot 2.7.x之前的配置清单为META-INF/spring.factories,之后的配置清单为META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports,老的配置向下兼容存放在META-INF/spring.factories中
  • 查看SpringBoot框架约定的自动化配置清单文件:
    在这里插入图片描述

基于redis的自动装配

  • 引入redis的start依赖项
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
  • RedisAutoConfiguration自动配置类
    在这里插入图片描述
@AutoConfiguration
// 通过判断类路径中是否存在特定类,来动态决定是否加载某个配置
@ConditionalOnClass({RedisOperations.class}) 
// 将带有@ConfigurationProperties注解的类纳入Spring容器管理,并实现yaml配置文件与该类属性的自动绑定
@EnableConfigurationProperties({RedisProperties.class})
// 主动主动引入外部配置
@Import({LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class})
public class RedisAutoConfiguration {
    @Bean
    @ConditionalOnMissingBean(name = {"redisTemplate"})
    @ConditionalOnSingleCandidate(RedisConnectionFactory.class)
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<Object, Object> template = new RedisTemplate();
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }
    @Bean
    @ConditionalOnMissingBean
    @ConditionalOnSingleCandidate(RedisConnectionFactory.class)
    public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
        return new StringRedisTemplate(redisConnectionFactory);
    }
}

应用启动参数

java -jar demo.jar --spring.profiles.active=test
在默认 application.properties 或 application.yml 基础上追加项目中的 application-test.properties 或 application-test.yaml
----
java -jar demo.jar --spring.config.additional-location=./application-test.yml
在默认 application.properties 或 application.yml 基础上追加本地硬盘上的 application-test.yml
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大能嘚吧嘚

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值