大家好,欢迎来到IT知识分享网。
文章目录
前言
Spring是一个开源的Java框架,旨在简化企业级Java应用程序的开发。它提供了一个全面的编程和配置模型,可用于构建各种类型的应用程序,包括Web应用程序、企业应用程序、移动应用程序等,在项目的开发中每位研发都会与之打交道。
一、Spring是什么?
Spring是一个大的bean 容器,管理各种各样的bean 对象,以spirng为基础,衍生处理Spring-mybatis,Spring-mvc ,spring-boot, spring-cloud 等框架;
二、Spring的两大特性:
Spring 的两大特性IOC和AOP 都依赖于Spring容器中各种bean 来实现,所以想要了解Spring 的特性,就先需要知道Spring 是怎么创建和管理Bean的;
2.1 IOC(控制反转):
控制反转,Spring 帮我们管理各种bean ,我们可以通过注入的方式使用这个bean,而不关系Bean 具体的创建和销毁过程;
2.1.1 Bean 文件的加载:
2.1.2 Bean的创建:
从beanDefinition 获取需要创建的bean 然后进行遍历,通过改bean 对应的class ,进而获取到对应class 中的构造方法,然后通过反射进行bean 对象的创建;
2.1.3 Bean的属性注入:
Bean 对象创建后,bean 中的属性都是null 或者初始值,所以需要通过依赖注入的方式完成属性注入;
2.1.4 Bean 的初始化:
Bean 对象在完成属性注入后,执行初化 方法完成资源的预加载工作;在Bean 初始化之前和之后 spring 扩展了监听的方法postProcessBeforeInitialization和 postProcessAfterInitialization 可以对bean 的创建过程进行干预;
初始化方法的执行:
2.1.5 Bean 的代理增强:
Bean 初始化完成之后,如果Bean 有AOP 切面,需要为其创建代理对象,然后将代理对象放入的Bean 的单例池中;
2.2 AOP :
Spring 在启动时获取所以定义的AOP切面,并获取到对应类及其对应方法,Bean 在创建完成,如果发现改Bean 需要进行AOP 则为其生成代理类,并将其原有的普通对象以代理对象属性的方式注入到代理类中。
2.2.1 代码演示:
(1)在springboot 项目中 引入aop 依赖:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency>
(2)定义配置类 MyConfig:
@EnableAspectJAutoProxy @ComponentScan(basePackages = "com.example.springdabaihua.annotion.bean.service") public class MyConfig {
}
(3)在对应的ComponentScan 扫描路径下定义Aop切面和测试类:
@Component public class UserService {
@Resource private OrderService OrderService; public void test() {
System.out.println("userService bean finish"); UserService userService1 = MyConfigTest.context.getBean(UserService.class); this.test1();// 断点查看当前 this对象 和 userService1 的区别 } private void test1() {
} } @Component public class OrderService {
} public class MyConfigTest {
public static ConfigurableApplicationContext context; public static void main(String[] args) {
context = new AnnotationConfigApplicationContext(MyConfig.class); UserService userService = context.getBean(UserService.class); System.out.println(userService); userService.test(); } }
- userService1 是cglib 代理对象;
- userService1 中的OrderService 属性值是null
- userService1 中有个target 属性对应 UserService的普通bean 对象
- UserService的普通bean 对象 中的OrderService 属性是有值的
2.2.2 代码演示mysql @Transactional 注解普通对象调用失效的场景:
(1) 在pom 增加mybatis-plus 的依赖:
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> </dependency> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.5.2</version> </dependency> <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java --> <dependency> <groupId>com.mysql</groupId> <artifactId>mysql-connector-j</artifactId> </dependency>
(2) MyConfig DataSource注入:
package com.example.springdabaihua.annotion.bean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.EnableAspectJAutoProxy; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.datasource.DataSourceTransactionManager; import org.springframework.jdbc.datasource.DriverManagerDataSource; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.EnableTransactionManagement; import javax.sql.DataSource; @Configuration //@Component @EnableTransactionManagement @EnableAspectJAutoProxy @ComponentScan(basePackages = "com.example.springdabaihua.annotion.bean.service") public class MyConfig {
@Bean public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource(); dataSource.setUrl("jdbc:mysql://localhost:3406/testaop?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&useAffectedRows=true&useSSL=false&zeroDateTimeBehavior=convertToNull&serverTimezone=GMT%2B8"); dataSource.setUsername("root"); dataSource.setPassword("ddsoft"); return dataSource; } // @Bean // public JdbcTemplate jdbcTemplate(DataSource dataSource) {
// return new JdbcTemplate(dataSource); // } // // // @Bean // public DataSourceTransactionManager transactionManager(DataSource dataSource) {
// return new DataSourceTransactionManager(dataSource); // } @Bean public JdbcTemplate jdbcTemplate() {
return new JdbcTemplate(dataSource()); } @Bean public DataSourceTransactionManager transactionManager() {
return new DataSourceTransactionManager(dataSource()); } }
(3)测试代码:
@Component public class ShopService {
@Autowired private JdbcTemplate jdbcTemplate; @Transactional public void testShopService(){
jdbcTemplate.execute("insert into user (name,age) value ('张三',23)"); System.out.println("testShopService 调用"); // "123".substring(8); 测试事务是否生效 a(); } // 测试事务传播 @Transactional(propagation = Propagation.NEVER) public void a() {
} } public class MyConfigTest {
public static ConfigurableApplicationContext context; public static void main(String[] args) {
context = new AnnotationConfigApplicationContext(MyConfig.class); // UserService userService = context.getBean(UserService.class); // System.out.println(userService); // userService.test(); ShopService shopService = context.getBean(ShopService.class); System.out.println(shopService); shopService.testShopService(); } }
mysql table:
CREATE TABLE `user` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键', `name` varchar(30) DEFAULT '' COMMENT '姓名', `age` int(11) DEFAULT '0' COMMENT '年龄', PRIMARY KEY (`id`) USING BTREE ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用户';
(4)测试场景:
- 验证事务的传播:
通过直接调用a() ,数据可以正常插入,事务失效,失效的原因,a()方法的调用时通过改类普通对象调用的而不是通过增强的代理对象调用,导致事务失效,如果在改类中重新注入该类的bean 在执行会报错,因为此时使用的shopService 的代理对象:
- 验证事务的回滚和提交:
注释掉a() 方法,注释掉 MyConfig 的 @Configuration 注解
虽然报错了,但是数据也被正常插入到数据库,事务失效原因,在注释掉@Configuration 后, 此时 jdbcTemplate 和 DataSourceTransactionManager 中放入的dataSource() 是两个不同的对象,导致在开启事务后 ,从DataSourceTransactionManager和 jdbcTemplate 获取到的连接不是同一个连接,造成事务失效;通过 @Configuration 注解在调用 dataSource() 方法时, 实际上使用了MyConfig 的代理对象,然后执行dataSource() 方法,此时会先找是否存在dataSource 这个bean 有就直接返回,没有在进行创建,所以开启了 @Configuration 之后获取到的 dataSource bean 是同一个;
2.3 IOC和 AOP的关系 :
IOC(Inversion of Control)和AOP(Aspect-Oriented Programming)是两种不同的编程概念,它们在某些方面是互补关系。
- 控制反转(IOC):IOC是一种设计原则,它将应用程序的控制权从代码中转移到外部容器中。通过IOC容器,开
发者将对象的创建、依赖注入和生命周期管理交给容器来处理。IOC的目标是解耦应用程序组件之间的依赖,提高代码的可扩展性和可测试性。 - 面向切面编程(AOP):AOP是一种编程范式,它允许开发者在不修改原始代码的情况下,
关注点定义为切面,并将它们与核心业务逻辑的连接点进行织入,可以实现横向关注点的复用和模块化。 - IOC与AOP的关系:IOC和AOP可以结合使用,以实现更灵活和可维护的代码结构。在使用IOC容器(如Spring)的同时,开发者可以通过AOP机制将横切关注点应用到应用程序中的不同连接点上。这样可以将通用的横切关注点(例如日志记录、安全性控制)从核心业务逻辑中解耦,并实现代码的重用和模块化。
- IOC 中创建的Bean 会判断是否改Bean 有aop 的逻辑,从而会
为其生成代理对象,然后将代理对象的bean注入到容器中,以便于后续再调用代理对象的方法时可以顺利进入aop 逻辑;
2.4 扩展点 :
2.4.1 接口和抽象类的区别:
除了语法不同外,接口和抽象类的编程方式是不同的:
- 接口:
自上向下,只需要定义方法不关心实现; - 抽象类类:
自下向上,将共性的东西进行抽离 ,定义共有属性的类对象;
2.4.2 beanFactory和 beanPost :
- BeanFactory(Bean工厂):BeanFactory是Spring框架的核心接口,它负责创建和管理应用程序中的所有Bean。BeanFactory是一个IoC容器,它通过读取配置文件或注解等方式,根据配置将Bean实例化并将它们的依赖关系注入到相应的对象中。BeanFactory是Spring的基础架构,提供了IoC和DI功能的核心实现,
bean 操作的根接口,BeanFactory可以访问并修改所有的bean 对象,开发层面基本不使用。 - BeanPostProcessor(Bean后置处理器):BeanPostProcessor是Spring框架提供的扩展点之一,它允许用户在Bean实例化、依赖注入和初始化等过程中对Bean进行自定义的处理操作。BeanPostProcessor接口包括两个主要的方法:postProcessBeforeInitialization()在Bean初始化之前被调用,postProcessAfterInitialization()在Bean初始化之后被调用。用户可以通过实现BeanPostProcessor接口来自定义Bean的初始化逻辑、修改Bean的属性或实现其他自定义操作,
开发者可以实现 BeanPostProcessor 干预bean 的创建过程。 - BeanFactory是一个根接口,它定义了在应用程序中对Bean进行管理的基本操作,而BeanPostProcessor是一个扩展接口,它允许开发者在Bean的生命周期中插入自定义的处理逻辑。在Spring框架中,BeanFactory被作为Bean的工厂使用,负责创建和管理Bean的生命周期,而BeanPostProcessor用于在Bean的和初始化过程中添加自定义的处理逻辑。
总结
此篇文章只对Spring 的核心原理进行大概的讲解,后续文章会对bean 的推断构造方法,三级缓存,AOP 代理增强,Bean的生命周期进行详细讲解。
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/118806.html








通过 @Configuration 注解在调用 dataSource() 方法时, 实际上使用了MyConfig 的代理对象,然后执行dataSource() 方法,此时会先找是否存在dataSource 这个bean 有就直接返回,没有在进行创建,所以开启了 @Configuration 之后获取到的 dataSource bean 是同一个;