spring
两大核心: 控制反转IoC 和AOP
- 控制反转/依赖注入:对象不用自己找依赖,Spring容器自动"送货上门",实现松耦合。
- 面向切面编程:像切洋葱一样把通用功能(日志、事务)横向抽取,让核心业务更纯净。
- 数据访问支持:用统一的方式操作各种数据库,告别繁琐的JDBC代码和不同数据库的兼容问题。
- 声明式事务管理 :只需一个
@Transactional注解,复杂的事务管理就像"开关"一样简单可控。 - 高度模块化设计:像乐高积木,需要什么拿什么,不必引入整个框架。
- 强大测试支持:专为测试而生,轻松模拟完整Spring环境进行单元和集成测试。
spring的八大模式
-
简单工厂模式:获取 bean 的时候可以通过简单工厂模式(静态工厂模式)来获取
-
工厂方法模式:FactoryBean是典型的工厂方法模式。在配置文件中通过factory-method属性来指定工厂方法,该方法是一个实例方法
-
单例模式:Spring用的是双重判断加锁的单例模式。
-
代理模式:aop就是使用了动态代理实现的
-
装饰器模式:javase中io流是非常典型的装饰器模式,Spring 使用装饰器来增强 Bean 的功能,如属性访问、类型转换等
-
观察者模式:spring容器生命周期管理,Spring 容器自己就是个"大主播",在启动、刷新、关闭这些关键节点时,会发布事件通知所有"粉丝"(内置监听器),让它们执行相应的处理逻辑
-
策略模式:事务策略,Spring 根据资源路径的前缀(
classpath:、file:、http:)自动选择不同的加载策略 -
模板方法模式:Spring中的JdbcTemplate类就是一个模板类。它就是一个模板方法设计模式的体现。在模板类的模板方法execute中编写核心算法,具体的实现步骤在子类中完成
控制反转的理论
java
//将对象的创建权交出去,将对象和对象之间关系的管理权交出去,由第三方容器来负责创建与维护
控制反转的常用方法(依赖注入3种)
java
控制反转常见的实现方式:依赖注入(Dependency Injection,简称DI)
1.set方法注入(// 使用set方式注入,必须提供set方法,来给属性赋值)
2.构造方法注入
3.字段注入(底层通过反射机制 ,通过反射获取字段,创建对象)
OOD五大原则
- SRP :单一职责原则 一个类只干一件事
- OCP:开闭原则 不修改代码,只新增代码
- LSP :里氏替换 子类要能当父类使用,即使换了也不出错
- ISP : 接口隔离原则 接口要专一,不要强迫去实现用不到的方法
- DIP:依赖倒置原则 依赖抽象而不是具体,就是所谓的面向接口编程
spring的七大模块

bean的使用以及在配置文件里面的配置
- id属性:代表对象的唯一标识。可以看做一个人的身份证号。
- class属性:用来指定要创建的java对象的类名,这个类名必须是全限定类名(带包名)。
xml
<bean id="userBean" class="com.jkweilai.spring.bean.User"></bean>
创建对象时确实调用了无参数构造方法(底层创建的原理:通过反射,调用无参构造,如果不给无参构造,就会报错)
java
// dom4j解析beans.xml文件,从中获取class的全限定类名
// 通过反射机制调用无参数构造方法创建对象
Class clazz = Class.forName("com.jkweilai.spring.bean.User");
Object obj = clazz.newInstance();
bean创建好之后 存在大map中了

xml
<bean id="userBean" class="com.jkweilai.spring.bean.User"/>
创建的对象,会有一个id,一个id对应一个对象,然后存在大map中。
当你想获取bean的时候,你就要从spring容器上下文里面去获取,通过id获取
java
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml","spring.xml");
java
Object userBean = applicationContext.getBean("userBean");
spring集成的日志是 logback日志框架
引入依赖:
xml
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.4.14</version>
</dependency>
logback.xml配置文件,必须放在类的根路径下
xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!-- 定义日志输出格式 -->
<property name="CONSOLE_LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n"/>
<property name="FILE_LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n"/>
<!-- 控制台输出 Appender -->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${CONSOLE_LOG_PATTERN}</pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<!-- 文件输出 Appender -->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 日志文件路径 -->
<file>logs/application.log</file>
<encoder>
<pattern>${FILE_LOG_PATTERN}</pattern>
<charset>UTF-8</charset>
</encoder>
<!-- 滚动策略 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 按天归档 -->
<fileNamePattern>logs/application.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<!-- 单个文件最大 100MB -->
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!-- 保留 30 天的历史 -->
<maxHistory>30</maxHistory>
</rollingPolicy>
</appender>
<!-- 设置日志级别 -->
<!-- Spring Framework 的日志级别 -->
<logger name="org.springframework" level="INFO"/>
<!-- 项目的包路径,设置为 DEBUG 以便调试 -->
<logger name="com.jkweilai" level="DEBUG"/>
<!-- 根日志配置 -->
<root level="INFO">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="FILE"/>
</root>
</configuration>
日志级别
- TRACE:最低级别,用于记录所有日志信息。
- DEBUG:用于记录调试信息,便于开发人员进行调试,但不适用于生产环境。
- INFO:用于记录生产环境下的信息,如启动信息、用户登录信息等。
- WARN:用于记录警告信息,表示程序可能出现潜在问题。
- ERROR:用于记录错误信息,表示程序已经出现错误,需要进行处理。
- FATAL:最高级别,用于记录致命错误信息,表示程序已经无法继续执行,需要进行紧急处理。
- OFF:关闭所有的日志记录。
如何使用日志框架
java
//创建日志工厂
Logger logger = LoggerFactory.getLogger(FirstSpringTest.class);
//调用日志方法
logger.info("我是一条日志消息");
bean的作用域
- singleton:默认的,单例。
- prototype:原型。每调用一次getBean()方法则获取一个新的Bean对象。或每次注入的时候都是新对象。
- request:一个请求对应一个Bean。仅限于在WEB应用中使用。
- session:一个会话对应一个Bean。仅限于在WEB应用中使用。
- application:一个应用对应一个Bean。仅限于在WEB应用中使用。
- websocket:一个websocket生命周期对应一个Bean。仅限于在WEB应用中使用。
- 自定义scope:几乎用不上,感兴趣的可以研究。
BeanFactory和FactoryBean的区别
Spring IoC容器的顶级对象,BeanFactory被翻译为"Bean工厂",在Spring的IoC容器中,"Bean工厂"负责创建Bean对象。
BeanFactory是工厂。(创建bean的)
FactoryBean:它是一个Bean,是一个能够辅助Spring实例化其它Bean对象的一个Bean。
Bean的生命周期
- 第一步:实例化Bean
- 第二步:Bean属性赋值
- 第三步:初始化Bean
- 第四步:使用Bean
- 第五步:销毁Bean

spring解决循环依赖的机理

首先:
1.创建A,通过实例化,创建A对象,然后将A提前曝光,将他放在三级缓存里面
2.发现A头上有@Autowired属性B,然后,将B创建,然后也曝光出去,将B放在三级缓存中
3.因为你不确定 B的类型是什么 有可能是代理对象,或者原始对象,不确定啊!
所以放在三级缓存里面确定一下,然后在跑半成品bean里面去创建,最后创建好,就将成熟bean放一级缓存里面。
Spring 不能解决的循环依赖场景有哪些
- 构造器注入:因为构造器注入要求在实例化之时就必须提供完整的依赖对象,而那时Bean本身都还未创建,更无法提前曝光,所以无法解决。
- 原型Bean(Prototype):Spring不缓存原型Bean,每次都会重新创建,因此无法利用三级缓存机制。
声明Bean的注解,这个是声明bean
-
@Component(@Controller、@Service、@Repository这三个注解都是@Component注解的别名)
-
@Controller
-
@Service
-
@Repository
-
控制器类上使用:Controller===》控制访问层
-
service类上使用:Service ===》业务逻辑层
-
dao类上使用:Repository===》mapper层 数据访问层
给属性赋值的四个,这个是声明属性
- @Value ==》(简单类型)
- @Autowired==》注入非简单类型 ,默认根据类型装配,spring框架自己的
- @Qualifier==》@Autowired注解,在@Qualifier注解中指定Bean名称
- @Resource==》默认根据名字装配,然后根据类型装配,属于JDK扩展包
关于Configuration和ComponentScan和Bean
@Configuration==》配置类,@ComponentScan==扫描@component的衍生注解,比如@service,@controller ,纳入ioc@Bean==》可以将自己new的对象,纳入ioc容器管理

面向切面编程AOP
AOP的优点:
- 第一:代码复用性增强。
- 第二:代码易维护。
- 第三:使开发者更关注业务逻辑
AOP的七大术语:
- 连接点 Joinpoint:程序执行过程中可以插入切面的具体位置(如方法执行前、方法正常返回后、方法抛出异常时、方法最终结束时等)
- 切点 Pointcut :切点本质上就是一个"位置表达式",用来精确指定在哪些连接点织入切面
- 通知 Advice:在切点处执行的增强逻辑代码
- 切面 Aspect:切点 + 通知
- 织入 Weaving:将切面应用到目标对象的过程
- 代理对象 Proxy:被增强后产生的对象
- 目标对象 Target:原始的需要被增强的对象
切点表达式
访问控制权限修饰符:
- 可选项。
- 没写时会匹配所有访问权限的方法。
- 写public就表示只包括公开的方法。
返回值类型:
- 必填项。
*表示返回值类型任意。
全限定类名:
- 可选项。
- 在类路径中,
..表示当前包及其所有子包 - 省略时表示所有的类。
方法名:
- 必填项。
*表示所有方法。set*表示所有的set方法。
形式参数列表:
- 必填项
()- 无参数方法(..)- 任意参数(0个或多个)(*)- 恰好一个参数,类型任意(String)- 恰好一个String类型参数(String, *)- 恰好两个参数,第一个是String,第二个任意(*, String)- 恰好两个参数,第二个是String,第一个任意
异常:
- 可选项。
- 省略时表示任意异常类型。
text
execution([访问控制权限修饰符] 返回值类型 [全限定类名]方法名(形式参数列表) [异常])
java
execution(public * com.jkweilai.mall.service.*.delete*(..))
● public:只匹配public方法
● *:返回值类型任意
● com.jkweilai.mall.service.*:com.jkweilai.mall.service包下的直接子类(不包含子包)
● delete*:方法名以delete开头
● (..):参数任意(0个或多个)
使用Spring的AOP(注解的方式
基于AspectJ的AOP注解式开发
1.要目标类,以及目标方法
2.定义切面类,使用@Aspect,在方法上,写切点表达式,发通知,用@Before
3.将目标类 以及 切面类 都纳入ioc bean的管理,加入@Component
java
// 切面类
@Aspect
@Component
@Order(1) //设置优先级
public class MyAspect {
// 切点表达式
@Before("execution(* com.jkweilai.spring.service.OrderService.*(..))")
// 这就是需要增强的代码(通知)
public void advice(){
System.out.println("我是一个通知");
}
}
通知类型
通知类型包括:
- 前置通知:@Before 目标方法执行之前的通知
- 后置通知:@After 目标方法不管是否成功结束,后置通知都会执行(即时有未捕获的异常)
- 返回通知:@AfterReturning 目标方法成功执行返回后执行的通知(目标方法出现未捕获的异常时,不会执行)
- 异常通知:@AfterThrowing 目标方法发生异常后执行的通知
- 环绕通知:@Around 目标方法执行之前和之后都可添加通知,可以控制目标方法是否执行
执行顺序:
- 正常执行:@Around前半 → @Before → 目标方法 → @AfterReturning → @After → @Around后半
- 异常执行:@Around前半 → @Before → 目标方法 → @AfterThrowing → @After → @Around后半
- **注意:**目标方法出现异常,并且最终异常没有捕获的话,@Around后半 不会执行。
理解:
around = Before + after ,但是多了,可以控制中间函数的
顺序:
普通:前置 ==》 执行 ==》发生异常 ==》后置也会执行
如果是环绕round的话:发生异常 ,后置就不会执行了
对于事务的处理
- 在一个业务流程当中,通常需要多条DML(insert delete update)语句共同联合才能完成,这多条DML语句必须同时成功,或者同时失败,这样才能保证数据的安全。
- 多条DML要么同时成功,要么同时失败,这叫做事务。
处理的过程
- 第一步:开启事务 (start transaction)
- 第二步:执行核心业务代码
- 第三步:提交事务(如果核心业务处理过程中没有出现异常)(commit transaction)
- 第四步:回滚事务(如果核心业务处理过程中出现异常)(rollback transaction)
事务的四个特性
- A 原子性:事务是最小的工作单元,不可再分。
- C 一致性:事务要求要么同时成功,要么同时失败。事务前和事务后的总量不变。
- I 隔离性:事务和事务之间因为有隔离性,才可以保证互不干扰。
- D 持久性:持久性是事务结束的标志。

spring实现对事务的方式(注解方式)
事务的传播行为 七种
- REQUIRED:支持当前事务,如果不存在就新建一个(默认)【没有就新建,有就加入】
- SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行**【有就加入,没有就不管了】**
- MANDATORY:必须运行在一个事务中,如果当前没有事务正在发生,将抛出一个异常**【有就加入,没有就抛异常】**
- REQUIRES_NEW:开启一个新的事务,如果一个事务已经存在,则将这个存在的事务挂起**【不管有没有,直接开启一个新事务,开启的新事务和之前的事务不存在嵌套关系,之前事务被挂起,挂起就是把当前事务暂停,等新事务完成后,再恢复继续执行】**
- NOT_SUPPORTED:以非事务方式运行,如果有事务存在,挂起当前事务**【不支持事务,存在就挂起】**
- NEVER:以非事务方式运行,如果有事务存在,抛出异常**【不支持事务,存在就抛异常】**
- NESTED:如果当前正有一个事务在进行中,则该方法应当运行在一个嵌套式事务中。被嵌套的事务可以独立于外层事务进行提交或回滚。如果外层事务不存在,行为就像REQUIRED一样。【当前有事务的话,就在这个事务里再嵌套一个完全独立的事务,嵌套的事务可以独立的提交和回滚。当前没有事务就和REQUIRED一样。嵌套事务的特点是:外层回滚会导致内层回滚】
一个事务中,如果当前没有事务正在发生,将抛出一个异常**【有就加入,没有就抛异常】** - REQUIRES_NEW:开启一个新的事务,如果一个事务已经存在,则将这个存在的事务挂起**【不管有没有,直接开启一个新事务,开启的新事务和之前的事务不存在嵌套关系,之前事务被挂起,挂起就是把当前事务暂停,等新事务完成后,再恢复继续执行】**
- NOT_SUPPORTED:以非事务方式运行,如果有事务存在,挂起当前事务**【不支持事务,存在就挂起】**
- NEVER:以非事务方式运行,如果有事务存在,抛出异常**【不支持事务,存在就抛异常】**
- NESTED:如果当前正有一个事务在进行中,则该方法应当运行在一个嵌套式事务中。被嵌套的事务可以独立于外层事务进行提交或回滚。如果外层事务不存在,行为就像REQUIRED一样。【当前有事务的话,就在这个事务里再嵌套一个完全独立的事务,嵌套的事务可以独立的提交和回滚。当前没有事务就和REQUIRED一样。嵌套事务的特点是:外层回滚会导致内层回滚】