Spring进阶篇

一、spring复习

1、什么是spring,对spring的认识理解?

spring是一个轻量级开源的一站式的Java开发框架,目的是为了简化企业级开发。

2、spring的优缺点

优点:轻量级、开源的、简单、IOC(控制反转)和AOP面向切面编程

缺点:配置多,很多都是模板化的配置,管理很多依赖

3、理解IOC和AOP

IOC:控制反转,把项目中创建对象的权力交给Spring框架,由spring框架统一管理项目中的对象,由spring框架生成的对象,称为一个bean对象,spring可以对bean对象进行功能上的增强。

AOP:面向切面编程,使用动态代理的方式,为目标对象提供代理对象,在不修改目标类中的代码时,为目标类添加额外的功能,将额外的功能横切到目标类中。

4、IOC和DI的区别

IOC是一种设计原则,强调控制权的反转,是一种宏观的概念

DI:依赖注入,是实现IOC的具体技术手段,侧重于依赖对象的注入过程。在IOC的基础上把对象注入到我们需要的地方

5、spring注入对象的方式

基于xml配置方式:

属性注入:是使用setter方法来实现

java 复制代码
package com.example;

public class DataSource {
    private String url;
    private String username;
    private String password;

    public void setUrl(String url) {
        this.url = url;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    // Getter 方法可按需添加
} 
java 复制代码
package com.example;

public class UserService {
    private DataSource dataSource;

    public void setDataSource(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    // 业务方法
    public void doSomething() {
        // 使用 dataSource 进行操作
    }
}
java 复制代码
<?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">

    <!-- 定义数据源 Bean -->
    <bean id="dataSource" class="com.example.DataSource">
        <property name="url" value="jdbc:mysql://localhost:3306/test"/>
        <property name="username" value="root"/>
        <property name="password" value="password"/>
    </bean>

    <!-- 定义服务 Bean,注入数据源 -->
    <bean id="userService" class="com.example.UserService">
        <property name="dataSource" ref="dataSource"/>
    </bean>
</beans>  

构造方法注入:通过构造函数来实现的

java 复制代码
package com.example;

public class DataSource {
    private String url;
    private String username;
    private String password;

    public DataSource(String url, String username, String password) {
        this.url = url;
        this.username = username;
        this.password = password;
    }

    // Getter 方法可按需添加
}
java 复制代码
package com.example;

public class UserService {
    private DataSource dataSource;

    public UserService(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    // 业务方法
    public void doSomething() {
        // 使用 dataSource 进行操作
    }
} 
java 复制代码
<?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">

    <!-- 定义数据源 Bean -->
    <bean id="dataSource" class="com.example.DataSource">
        <constructor-arg value="jdbc:mysql://localhost:3306/test"/>
        <constructor-arg value="root"/>
        <constructor-arg value="password"/>
    </bean>

    <!-- 定义服务 Bean,注入数据源 -->
    <bean id="userService" class="com.example.UserService">
        <constructor-arg ref="dataSource"/>
    </bean>
</beans>

注解方式:

属性注入:是使用@Autowired 注解来实现属性注入

java 复制代码
package com.example;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserService {
    @Autowired
    private DataSource dataSource;

    // 业务方法
    public void doSomething() {
        // 使用 dataSource 进行操作
    }
}

构造方法注入:同样可以使用 @Autowired 注解实现构造方法注入

java 复制代码
package com.example;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserService {
    private DataSource dataSource;

    @Autowired
    public UserService(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    // 业务方法
    public void doSomething() {
        // 使用 dataSource 进行操作
    }
}

6、自动注入有哪些注解

1、使用spring框架中提供的**@Autowired注解**,可以添加到要注入的属性上面,或者属性的set方法上,如果直接添加到属性上面,那么set方法可以不需要添加。

默认情况下,要注入的属性对象不能空@Autowired(required=true)

注入时,查找bean的方式有两种:

1、当只有一个匹配的Bean时默认是通过属性的类型查询

2、当出现多个匹配的Bean时,需要使用@Qualifier(value=对象ming),或者使用@Primary,Spring 会优先选择被 @Primary 注解标记的 Bean 进行注入。

2、使用jdk中提供的注解**@Resource**

查找bean也是有两种方式:

1、通过名称查询:会根据字段类型在容器中查找实现了该接口的 Bean

2、如果按类型查找时存在多个匹配的 Bean,@Resource 会抛出 NoUniqueBeanDefinitionException 异常。此时,可以通过指定 name 属性来明确要注入的 Bean。@Resource(name = "adminDao") 通过对象名查询

@Resource和@Autowried的区别?

1、来源不同:@Resource 是jdk提供的,@Autowired是spring提供的

2、查找方式不同::@Resource 默认按名称( @Component("userDaoImpl"))查找 Bean,@Autowired默认按类型(类名)查找 Bean。

3、支持的属性不同:@Resource(name=Bean的名称,type=Bean的类型),@Autowired(required=true) 表示注入的依赖必须存在,默认是true

java 复制代码
import javax.annotation.Resource;
import org.springframework.stereotype.Service;

@Service
public class UserService {
    // 指定名称和类型
    @Resource(name = "userDaoImpl", type = UserDaoImpl.class)
    private UserDao userDao;
}
java 复制代码
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserService {
    // 依赖可以为 null
    @Autowired(required = false)
    private UserDao userDao;
}

4、用法场景不同:@Resource适合明确指定了Bean名称进行注入,其可以保持代码的一致性。

@Autowried:在spring项目中主要依据类型进行注入,并结合@Qulifier注解处理多个匹配Bean的情况,使用其更加方便

7、spring中的bean和new的对象有什么区别?

bean对象是由spring框架创建的,根据我们的配置(事务、日志、统一异常处理),可以进行功能上的增强。

new对象是最原始的对象,没有任何功能的增强。

8、AOP中的术语有哪些,通知有哪些?

连接点:类中可以增强的方法

切入点:类中实际被增强的方法

通知:给切入点添加的功能

目标:被增强的类

代理:代理对象

通知类型:

1、前置通知:@Before,在方法执行前执行

2、后置通知:@After,在方法执行后执行

3、环绕通知:@Around,可以实现前置、后置、返回、异常通知

4、异常通知:@AfterThrowing,在出现异常时执行

5、返回通知:@AfterReturning,在目标方法正常执行并返回结果后执行,一旦出现异常就不执行

9、spring AOP实现的几种方式

xml配置方式

java 复制代码
<!-- 开启 AOP 自动代理 -->
    <aop:aspectj-autoproxy/>

    <!-- 定义目标对象 -->
    <bean id="userService" class="com.example.UserServiceImpl"/>

    <!-- 定义切面 -->
    <bean id="loggingAspect" class="com.example.LoggingAspect"/>

    <!-- 配置 AOP -->
    <aop:config>
        <!-- 定义切入点 -->
        <aop:pointcut id="userServiceMethods" expression="execution(* com.example.UserService.*(..))"/>
        <!-- 定义切面和通知 -->
        <aop:aspect ref="loggingAspect">
            <!-- 前置通知 -->
            <aop:before method="beforeAdvice" pointcut-ref="userServiceMethods"/>
            <!-- 后置通知 -->
            <aop:after method="afterAdvice" pointcut-ref="userServiceMethods"/>
        </aop:aspect>
    </aop:config>

注解方式

java 复制代码
 @Before("execution(* com.example.UserService.*(..))")
    public void beforeAdvice() {
        System.out.println("Before method execution");
    }

    @After("execution(* com.example.UserService.*(..))")
    public void afterAdvice() {
        System.out.println("After method execution");
    }

10、spring中事务的管理,实现方式有几种,原来是什么?

首先事务是数据库中的特性,在spring中,spring框架对事务开启,提交,回滚进行管理。

**编程式事务:**通过编写代码来管理事务的开始、提交、回滚,这种方式比较灵活,但代码量比较大,适用于需要精细控制事务边界的场景。

java 复制代码
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate;

@Service
public class UserServiceImpl implements UserService {
    @Autowired
    private JdbcTemplate jdbcTemplate;
    @Autowired
    private TransactionTemplate transactionTemplate;

    @Override
    public void transferMoney(int fromUserId, int toUserId, double amount) {
        transactionTemplate.execute(new TransactionCallback<Void>() {
            @Override
            public Void doInTransaction(TransactionStatus status) {
                try {
                    // 扣除转出用户的金额
                    jdbcTemplate.update("UPDATE users SET balance = balance - ? WHERE id = ?", amount, fromUserId);
                    // 模拟异常
                    if (true) {
                        throw new RuntimeException("Simulated exception");
                    }
                    // 增加转入用户的金额
                    jdbcTemplate.update("UPDATE users SET balance = balance + ? WHERE id = ?", amount, toUserId);
                } catch (Exception e) {
                    status.setRollbackOnly();
                    throw e;
                }
                return null;
            }
        });
    }
}    

声明式事务: 通过配置文件注解来定义事务的属性,Spring 会自动管理事务的开始、提交和回滚,这种方式代码侵入性小,适用于大多数场景。

java 复制代码
    <!-- 配置事务通知 -->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <tx:method name="transferMoney" propagation="REQUIRED"/>
        </tx:attributes>
    </tx:advice>
java 复制代码
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class UserServiceImpl implements UserService {
    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Transactional
    @Override
    public void transferMoney(int fromUserId, int toUserId, double amount) {
        // 扣除转出用户的金额
        jdbcTemplate.update("UPDATE users SET balance = balance - ? WHERE id = ?", amount, fromUserId);
        // 增加转入用户的金额
        jdbcTemplate.update("UPDATE users SET balance = balance + ? WHERE id = ?", amount, toUserId);
    }
}

11、声明式事务失效的场景

1、非public方法

2、异常没有抛出

3、数据库不支持事务(myIsam)

4、未指定异常回滚类型:默认情况下,Spring 的声明式事务仅在遇到运行时异常 (RuntimeException)和错误(Error)时回滚,对于受检查异常(如 IOExceptionSQLException 等)则不会回滚。

5、传播行为设置错误。

6、同类方法调用:当一个类中的非事务方法调用同一个类中的事务方法时,事务注解会失效。因为这种调用是通过this引用进行的,而非通过代理对象,所以事务注解不会生效。

7、异步方法调用:若在异步方法中使用事务注解,由于异步方法是在新线程中执行的,事务上下文无法传递,从而导致事务失效

12、springWeb的运行流程

1.用户发送出请求到前端控制器 DispatcherServlet。

  1. DispatcherServlet 收到请求调用 HandlerMapping(处理器映射器)。

  2. HandlerMapping 找到具体的处理器(可查找 xml 配置或注解配置),生成处理器对象及处理器拦截器(如果有),再一起返回给 DispatcherServlet。

  3. DispatcherServlet 调用 HandlerAdapter(处理器适配器)。

  4. HandlerAdapter 经过适配调用具体的处理器(Handler/Controller)。

6.Controller 执行完成向前端响应结果。

相关组件

DispatcherServlet:前端控制器,不需要程序员开发,由框架提供,在web.xml 中配置。

作用:统一处理请求和响应,整个流程控制的中心,由它调用其它组件处理用户的请求.
HandlerMapping:处理器映射器,不需要程序员开发)由框架提供。

作用:根据请求的 url 查找 Handler(处理器/Controller)

HandleAdapter:处理器适配器,不需要程序员开发,由框架提供。

作用:按照特定规则(HandlerAdapter 要求的规则)去执行 Handler
Handler:处理器,也称之为 Controller,需要程序员去开发

13、servlet过滤器和spring拦截器

首先过滤器是servlet中规范定义的,拦截器是spring中定义的。

过滤器只可以拦截所有进入到Java后端的请求,拦截器只能拦截进入到处理器(controller,web层)的请求。

14、spring和springboot的关系

springboot是对spring框架的搭建进行了封装,不是代替spring的,底层依然还是spring

15、spring常用的注解

声明Bean的注解

@RestController、@Service、@Repository都可以称为@Component,都是@component的衍生,这些注解在语义上更加明确,能让代码的可读性和可维护性得到提升。

@Component:基本组件

@RestController:控制层

@Service:业务层

@Repository:数据访问层

Bean的声明周期属性

@Scop设置类型:spring容器如何创建新建Bean的实例 @Scop(" ")

singleton:单例,一个spring容器中只有一个Bean的实例,默认的

protetype:每次调用创建一个新的对象

request:web项目中,给每个http request创建一个新Bean

注入Bean的注解

@Autowried、出现多个匹配的Bean与@Qualifier配合使用,@Resource

AOP的相关注解

@Aspect:声明一个切面类(包含通知的类)

@After:后置通知

@AfterReturning 返回通知

@Before:在方法执行之前执行

@AfterThrowing 异常通知

@Around:在方法执行之前与之后执行

SpringWeb的常用注解

@RequestMapping: 为类,方法定义访问请求地址@PostMapping:定义只允许 post 请求方式访问地址

@GetMapping:定义只允许 get 请求方式访问地址

@RequestBody:允许 request 的参数在 request 体中以 json 格式传递.

其他注解

@DateTimeFormat:此注解用于属性上,可以方便的把 Date 类型直接转化为我

们想要的格式.

@Transactional 注解放在类级别时,表示所有该类的公共方法都配置相同的事务属性信息。

SpringBoot 注解

@SpringBootApplication:

包含@SpringBootConfiguration、@EnableAutoConfiguration、

@ComponentScan 通常用在主类上;

统一异常处理注解

@RestControllerAdvice,@ExceptionHandler 用于统一异常处理,捕获指定的

异常.

配置类相关注解

@Configuration:声明当前类为配置类

@Bean:注解在方法上,声明当前方法的返回值为一个 bean,替代 xml 中的

方式

Spring 定时器

在启动类上添加 @EnableScheduling

在任务方法上添加 @Scheduled(cron = "*/6 * * * * ?")

16、spring中bean的声明周期

从宏观上来讲,可以分为5个阶段:

1、实例化 Instantiation

2、属性赋值 Populate

3、初始化 Initialization(最关键的,根据各种注解配置,在这里进一步落地实现)

4、将Bean对象放入到容器中使用

5、销毁 Destruction

17、spring中的Bean是线程安全的吗?

spring中的bean如果是单例,始终创建一个对象,所有请求公用一个对象,那么对该单例对象中的成员变量也就只有一份,所有请求共享。

在多用户访问时,可能出现问题,还有种情况,就是像每个请求中,都有属于自己的成员变量使用。所以单例Bean使用时,就有可能出现线程安全问题。

原型Bean每次请求都会创建一个新的对象,不会存在线程安全问题。

单例Bean线程安全问题解决:

如果成员变量是共享的,多线程 操作时,如**++**等操作,进行加锁控制,如果每一个请求中,都需要一个属于自己的成员变量:

1、单例bean修改为原型bean

2、使用ThreadLocal线程变量,为每一次的请求提供一个变量的副本。

在这里,单例Bean又分为:有状态Bean和无状态Bean

有状态Bean:

就是有成员变量,而且成员变量可以存储数据,就有可能多线程操作时出现问题。

无状态Bean:

注入对象,对象不进行数据存储,只是调用方法,每次请求中的参数数据都是相互隔离的

18、Bean的循环依赖

java 复制代码
class A{
B b;
}
class B{
A a;
}
public static void main(String[] args){
A a=new A();//创建A对象,关联对象b为null
B b=new B();//创建B对象,关联对象a为null
}
//修然A,B之间相互关联,但是创建对象时,没有任何问题

在spring中存在循环依赖的问题(spring已经解决了)

在spring中我们使用@Autowired注解,那么在创建A对象时,需要关联的B对象要注入,需要去创建B对象,创建B对象时,需要为关联的A注入值,但是此时A对象还没有创建完成,形成了一种死循环。

spring中是如何解决循环依赖的问题?

采用三级缓存来解决循环依赖问题

三级缓存就是三个map(ConcurrentHashMap)对象,来存储不同的对象。

一级缓存:singletonObjiects,一级缓存对象,主要存储创建、初始化完成的bean对象

二级缓存:earlysingletonObjects,二级缓存,主要存储实例化完成,但没有初始化完成的半成品对象。

三级缓存:singletonFactories:主要存储创建对象的工厂对象,创建A对象时还有一个创建A的工厂对象来创建A对象。

过程:

创建A对象时,需要用到B,A创建了一半,把他存储到二级缓存(earlysingletonobiects),把创建A的工厂对象存储到三级缓存中(singletonFactories),把半成品A注入到B中,B完成了创建,存储到一级缓存中(singletonObjects),把B注入到A中,A完成了创建,存储到一级缓存中。

19、spring boot自动装配原理

基本流程:

springboot启动时,首先对application.yml和pom.xml文件进行读取,获取到项目中使用到的第三方组件,然后读取spring.factories中的spring支持的配置类,最后加载项目中所使用到的组件配置类。
注解层面
启动类:

@SpringBootApplication 注解是一个复合注解


在@EnableAutoConfiguration 中有一个 @Import({AutoConfigurationImportSelector.class})注解,其中包含AutoConfigurationImportSelector 类.
根据pom.xml中的配置的相关依赖,进行选择性的加载,读取相关依赖的配置类

AutoConfigurationImportSelector 类中关键方法

​​​​​​​

相关推荐
舒一笑2 分钟前
一文简单记录打通K8s+Kibana流程如何启动(Windows下的Docker版本)
后端·elasticsearch·kibana
亦黑迷失2 分钟前
轻量级 Express 服务器:用 Pug 模板引擎实现动态参数传递
前端·javascript·后端
带刺的坐椅10 分钟前
qwen3 惊喜发布,用 ollama + solon ai (java) 尝个鲜
java·spring·solon·solon-ai·qwen3
慧一居士12 分钟前
Kafka批量消费部分处理成功时的手动提交方案
分布式·后端·kafka
命中的缘分43 分钟前
SpringCloud原理和机制
后端·spring·spring cloud
ErizJ43 分钟前
Golang|分布式索引架构
开发语言·分布式·后端·架构·golang
.生产的驴43 分钟前
SpringBoot 接口国际化i18n 多语言返回 中英文切换 全球化 语言切换
java·开发语言·spring boot·后端·前端框架
Howard_Stark1 小时前
Spring的BeanFactory和FactoryBean的区别
java·后端·spring
饮长安千年月1 小时前
学生管理系统审计
java·网络安全·代码审计
-曾牛1 小时前
Spring Boot中@RequestParam、@RequestBody、@PathVariable的区别与使用
java·spring boot·后端·intellij-idea·注解·spring boot 注解·混淆用法