深入探究Spring底层核心原理

作者:胡尚 时间:2023-03-05 08:32:16 

Spring底层核心原理

下面这几行代码是一个Spring的入门代码,第一行是通过java配置类 注解的方式创建一个Spring容器,第二行是通过XML配置文件的方式创建一个Spring容器

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
//ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
UserService userService = (UserService) context.getBean("userService");
userService.test();

最后两行代码就是从Spring容器中拿一个Bean对象并执行方法。那么Spring是如何创建一个Bean对象的嘞?

Bean的生命周期

  • 推断构造方法,并执行得到普通对象

  • 依赖注入

  • aware回调

  • 初始化前

执行BeanPostProcessor接口中的postProcessBeforeInitialization()方法

  • 初始化

执行有@PostConstruct注解的方法执行

InitializingBean接口中的afterPropertiesSet()方法

执行XML配置文件中init-method属性指定的方法

  • 初始化后

执行BeanPostProcessor接口中的postProcessAfterInitialization()方法

  • 普通对象/代理对象 存入容器中

  • 使用

  • 销毁

执行DisposableBean接口的destroy()方法

@PreDestroy注解的方法

XML 配置文件中destroy-method属性指定的方法

推断构造方法

如果没有写构造方法,那么Spring会执行默认空参的构造方法

如果显示写了一个构造方法,那么Spring就会使用这个构造方法,构造方法中如果有参数那么会进行依赖注入

如果显示写了多个构造方法并有空参的构造方法时,会执行空参的构造方法

如果显示写了多个构造方法没有空参的构造方法时,运行时会报错。解决方法是在要执行的构造方法上加@Autowired注解

AOP原理

cjlib和jdk两种 * 的实现都是有一个target属性来存储普通对象,代理对象中重写要执行的方法,首先执行增强逻辑,然后通过target属性去执行目标方法。伪代码如下:

public class UserServiceProxy extends UserService{
   private UserService target;
   public void test(){
       // TODO 增强业务
       target.test();
       // TODO 增强业务
   }
}

那么如何判断一个Bean是否需要进行AOP创建一个普通对象嘞?

  • 遍历所有有@Aspect注解的切面Bean

  • 遍历所有的方法

  • 判断方法上的切点表达式是否和当前正在创建的Bean匹配

  • 如果匹配则把这个切面中增强方法存入一个Map缓存中

真正要执行代理对象的方法时会从缓存中取出相应的增强逻辑来执行,再去执行目标方法。

Spring事务

Spring中如果要使用事务需要配置一个JdbcTemplate和一个事务管理器,它们俩都需要配置DataSource。

@ComponentScan("com.hs")
@Configuration
public class AppConfig {
  @Bean
  public JdbcTemplate jdbcTemplate() {
     return new JdbcTemplate(dataSource());
  }
  @Bean
  public PlatformTransactionManager transactionManager() {
     DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
     transactionManager.setDataSource(dataSource());
     return transactionManager;
  }
  @Bean
  public DataSource dataSource() {
     DriverManagerDataSource dataSource = new DriverManagerDataSource();
     dataSource.setUrl("jdbc:mysql://127.0.0.1:3306/hs?characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai");
     dataSource.setUsername("root");
     dataSource.setPassword("123456");
     return dataSource;
  }
}

Spring事务大致执行流程如下:

  • 判断要执行的方法上是否存在@Transcational注解

  • 如果存在则通过事务管理器创建一个connection连接对象

  • autoCommit设置为false

  • 去执行目标方法target.method()

  • 如果出现了异常则回滚rollback(),没有异常则提交commit()

如果上面的配置类中不加@Configuration注解,那么Spring的事务会失效。原因如下:

JdbcTemplate和事务管理器都需要DataSource,都会调用dataSource()获取。如果不加@Configuration注解,那么他们俩获取的DataSource就不是同一个。

代理对象中操作的是事务管理器的连接对象,而业务方法却是使用的JdbcTemplate,所以就导致了Spring事务失效。

而如果加上了@Configuration注解,在调用dataSource()时会先去Spring容器中找DataSource,如果没找到才回去调用方法创建一个。

来源:https://blog.csdn.net/qq_44027353/article/details/130223776

标签:Spring,底层,核心,原理
0
投稿

猜你喜欢

  • SpringCloud迈向云原生的步骤

    2023-08-21 22:59:46
  • java实现字符串和数字转换工具

    2021-08-28 15:50:19
  • Android项目实现视频播放器

    2022-10-05 07:53:35
  • C#操作目录与文件的方法步骤

    2023-11-23 20:45:52
  • Android RecyclerView基本使用详解

    2023-07-24 21:13:30
  • Android Studio 全屏沉浸式透明状态栏效果的实现

    2021-07-16 06:42:41
  • C#图片查看器实现方法

    2021-06-17 16:50:03
  • Flutter加载图片流程之ImageCache源码示例解析

    2023-07-04 01:56:23
  • JAVA通过Filter实现允许服务跨域请求的方法

    2022-08-02 02:17:46
  • Mybatis-Plus设置全局或者局部ID自增的实现

    2021-11-27 00:30:03
  • C# 多线程更新界面的错误的解决方法

    2022-01-20 15:52:21
  • C#端口扫描器的编写方法

    2023-12-17 17:47:24
  • JavaWeb实现用户登录与注册功能

    2022-08-30 17:23:48
  • Android库项目中的资源ID冲突的解决方法

    2023-11-04 05:32:53
  • java利用递归算法实现对文件夹的删除功能

    2023-07-26 06:37:02
  • java读写ini文件、FileOutputStream问题

    2023-11-29 08:50:13
  • OpenCV实现人脸识别简单程序

    2023-07-07 00:31:12
  • 用C语言实现一个扫雷小游戏

    2022-02-24 01:35:56
  • java实现动态代理示例分享

    2023-04-28 15:54:49
  • c#多线程中Lock()关键字的用法小结

    2022-07-08 04:33:27
  • asp之家 软件编程 m.aspxhome.com