Bean的生命周期
UserService.class ---> 无参数构造方法 (推断构造方法) ---> 普通对象 ---> 依赖注入(属性赋值) ---> 判断是否有Aware回调--->初始化前 (@PostConstruct) ---> 初始化 (InitializingBean) ---> 初始化后 (AOP) ---> 代理对象 ---> Bean
1、UserService.class
使用@Bean或者@Component来将此类声明为bean
@Component public class UserService { //beanName为userService @Autowired OrderService OrderService; //beanName为orderService }
UserService声明为bean,需要从Spring容器中注入OrderService的bean。
2、无参数构造方法 (推断构造方法)
没写构造方法:调用无参构造方法,实例化bean;
写一个构造方法:就使用这个构造方法(这一个无论有参无参)实例化bean
多个构造方法:就调用 无参构造方法 实例化bean,如果没有无参构造方法就会报错。除非某个构造方法上加了@Autowired,就会用这个 构造方法。
3、普通对象
上面那一步推断调用了构造方法后,就会创建一个普通对象(相当于new的一个)。
4、依赖注入(属性赋值)
找到那个添加了@Autowired的属性,然后给属性赋值。那怎么去找,先通过类型查找,查找到多个bean的话,再通过beanName在 Spring存储注册好的Map<beanName,bean对象>中查找。
5、Aware回调
Spring会判断该对象是否实现了BeanNameAware接口、 BeanClassLoaderAware接口、BeanFactoryAware接口,如果实现了,就表示当前 对象必须实现该接口中所定义的setBeanName()、setBeanClassLoader()、 setBeanFactory()方法,那Spring就会调用这些方法并传入相应的参数(Aware回 调)
6、初始化前 (@PostConstruct)
Spring会判断该对象中是否存在某个方法被@PostConstruct注解了,如果存在,Spring会调用当前对象的此方法(初始化前)
7、初始化 (InitializingBean)
紧接着,Spring会判断该对象是否实现了InitializingBean接口,如果实现了,就表示当前对象必须实现该接口中的afterPropertiesSet()方法,那Spring就会调用当前对象中的afterPropertiesSet()方法(初始化)
8、初始化后 (AOP)
流程:
1、找出所有的切面Bean(@Aspect)
2、遍历这些切面Bean
3、遍历每个切面Bean的方法
4、查找哪些方法适配当前要创建Bean的类(当前创建的Bean为UserService,查找的就是切面UserService的方法的切面类的方法),将这些方法缓存到map里面(Map<UserService.class,method>)。
将缓存方法的map中的访求拿出来,在代理类中执行,下面的target是被代理对象。
9、代理对象
如果使用了AOP就用 代理对象做为Bean
10、Bean
没有使用AOP应用 普通对象做为Bean
Spring事务
当我们在某个方法上加了@Transactional注解后,就表示该方法在调用时会开启Spring事 务,而这个方法所在的类所对应的Bean对象会是该类的代理对象。
Spring事务的代理对象执行某个方法时的步骤:
判断当前执行的方法是否存在@Transactional注解
如果存在,则利用事务管理器(TransactionMananger)新建一个数据库连接
修改数据库连接的autocommit为false
执行target.test(),执行程序员所写的业务逻辑代码,也就是执行sql
执行完了之后如果没有出现异常,则提交,否则回滚 Spring事务是否会失效的判断标准:某个加了@Transactional注解的方法被调用时,要判 断到底是不是直接被代理对象调用的,如果是则事务会生效,如果不是则失效
小细节:
为什么会普通对象的bean执行事务方法不生效?
扩展:@Transtaional和AOP一样都是创建代理对象的,所以用了@Transtaional,最后创建的Bean也会是代理对象,所以一个bean不是代理对象,调用@Transcational的方法,事务不会生效。
因为@Transactional,所以会创建一个代理对象,上面有事务的代理对象执行方法的步骤,其中代理对象的方法中 事务管理器创建一个连接应该是为了autocommit设置为false的,只有@Transactional实例出的代理对象bean才可以利用事务理器创建一个数据库连接,然后将autocommit设置为false,不设置成false就自动提交了。
而普通对象的bean只会执行业务,不会有上面的操作。
所以必须得是@Transactional实例化出的代理对象的bean。
当需要用到bean时:
spring首先是通过类型来查找Bean的,如果是多个,那么就会通过名字来查找bean(Spring使用了 Map<beanName,bean对象>的数据结构来存储已经注册的Bean ),如果是一个,那么就不需要通过名字查找了。
上面那个名字beanName,比如:
@Component public class OrderService{ //beanName为orderService }如果两个bean的 类型 和 beanName 都相同:
如果允许覆盖:就是@Bean产生的bean会覆盖@Component
如果不允许覆盖:就会报错
小扩展——声明bean的注解:
-
@Component:@Component 是一个通用的注解,用于将一个类标识为 Spring 管理的组件(Bean)。它可以应用于任何类,包括普通的 POJO 类、服务类、数据访问类等。
-
@Service:@Service 注解用于将一个类标识为服务层组件,通常用于表示业务逻辑的实现类。
-
@Repository:@Repository 注解用于将一个类标识为数据访问层组件,通常用于表示数据访问对象(DAO)。
-
@Controller:@Controller 注解用于将一个类标识为控制器组件,通常用于处理用户请求和控制应用程序的流程。
-
@Configuration:@Configuration 注解用于将一个类标识为配置类,该类通常包含了用 @Bean 注解声明的方法,用于配置和创建 Bean。
@Aspect不结合@Component会怎么样?
标签:构造方法,对象,Spring,bean,代理,Bean From: https://blog.csdn.net/weixin_68742131/article/details/136817216简称切面Bean,无法将切面类注册到Spring容器中,从而无法使用切面功能。