【Spring】一.小白初识——基石Framework

本文深入探讨Spring Framework的基础,包括如何创建Bean、依赖注入的原理、AOP动态代理的实现以及事务管理。通过示例代码解释了Spring如何通过XML或注解配置管理对象,并详细阐述了Bean的生命周期,特别是@Autowired注解的工作方式。此外,还介绍了AOP在创建代理对象中的角色,以及Spring如何处理事务,包括@Transactional注解的传播行为。
摘要由CSDN通过智能技术生成

这次来讲讲Spring家族里最基础的Spring Framework。为什么SpringBoot可以这么强大?Framewordk到底做了什么?参考最新的5.3.10-SNAPSHOT

Spring的Hello World

学习Spring你学的第一段代码是什么?我觉得应该是这一段

//读取xml
ClassPathXmlApplicationContext xmlApplicationContext = new ClassPathXmlApplicationContext("spring.xml");
//读取配置类
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
UserService userService = (UserService.class)applicationContext.getBean("userService");
userService.test();

得到一个Bean对象,然后就可以去调用。前面两行是创建Spring容器的方法。无论是前者的xml,还是3.0版本后新增的class方式去充当配置文件用注解定义。

xml目前基本已经out了,mvc时代会用的多一点。现在主要会用config.Class的方式,Spring Boot就是用了这种方式。

Spring容器管理

到底getBean和我们平时直接new一个有什么区别吗?相信这是每个入门者的疑问
简单贴一下UserService的代码

@Component
public class UserService{

    @Autowired
    private UserService self;

    public void test(){
        System.out.println("test");
    }
}

这里@Component就是取代xml配置文件的(后续会讲这个原理,@Bean是可以覆盖)实现Bean注入。
看到这里都懂了吧,容器管理的对象里面的self属性是有值的,而自己new的UserService对象是没有值的。——这个就叫依赖注入
表面就是给AutoWired注解属性赋值。

对象怎么变成一个Bean

我们知道返回的对象肯定不是一个普通的new出来的对象,是一个Spring代理的一个对象Bean对象。

  1. 利用类的构造方法实例化一个对象(这里会推断构造方法)
  2. 有了对象后会开始依赖注入
  3. BeanNameAware接口、 BeanClassLoaderAware接口、BeanFactoryAware接口,如果实现了,调用其并传入相应参数setBeanName()、setBeanClassLoader()、 setBeanFactory()(Aware回调)
  4. 是否有某个方法被@PostConstruct注解,如果有则执行(JSR-250的规范)
  5. InitializingBean接口,如果实现了,就 调用中的afterPropertiesSet()方法
  6. Spring会判断当前对象需不需要进行AOP,如果不需要那么Bean就创建完 了,如果需要进行AOP,则会进行动态代理并生成一个代理对象做为Bean(初始化 后)
值怎么来?

依赖注入的值怎么来? (特指Autowired)
Spring容器里面找
Spring会根据入参的类型和入参的名字去Spring中找Bean对象(以单例Bean为例, Spring会从单例池那个Map中去找):

  1. 先根据入参类型找,如果只找到一个,那就直接用来作为入参
  2. 如果根据类型找到多个,则再根据入参名字来确定唯一一个
  3. 最终如果没有找到,则会报错,无法创建当前Bean对象

先匹配类型,类型对了再看名字。还有JSR-250规范定义的@Resource默认按名字,也可以配置按类型。

AOP代理

创建一个Bean后会判断是否需要动态代理

  1. 找出所有的切面Bean (切片也是一个正常的Bean被Component修饰)
  2. 遍历切面中的每个方法,看是否写了@Before、@After等注解
  3. 如果写了,则判断所对应的Pointcut是否和当前Bean对象的类是否匹配
  4. 如果匹配则表示当前Bean对象有匹配的的Pointcut,表示需要进行AOP

所有要经过的方法会缓存起来

确认了需要动态代理后,通过cglib生成

cglib真正对类完全代理。
1.查找目标类上的所有非final 的public类型的方法定义;
2.将这些方法的定义转换成字节码;
3.将组成的字节码转换成相应的代理的class对象;
4.实现 MethodInterceptor接口,用来处理对代理类上所有方法的请求
基于ASM,字节码。对final修饰无能为力

  1. 生成代理类UserServiceProxy,代理类继承UserService
  2. 代理类中重写了父类的方法,比如UserService中的test()方法
  3. 代理类中还会有一个target属性,该属性的值为被代理对象(就是UserServer)
  4. 代理类中的test()方法被执行时的逻辑如下:
    a. 执行切面逻辑
    b. 调用target.void()
Spring事务

基于AOP,那真正代理的逻辑是怎样呢?

  1. 有没有@Transa
  2. 创建数据库链接conn(事务管理器datasource)
  3. 设置autoCommit=false,为了rollback
  4. @After 执行提交或者rollback

那怎么传播呢?
相信我们肯定都遇到过在Serve内调用旁边的方法发生错误没回滚的情况。
原因就是内部调用方法没用Bean去调用,所以我们这里需要self.a()去调用。要代理对象方法去调用@Transa的方法。就是自己注入自己

@Configurtaion不加的话事务会不生效,这里改变了代理逻辑,对于同一个方法不重复调用,确保jdbcTemplate和transactionManager的datasource是同一个

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值