面试深入之Spring(SpringBoot)
Bean的生命周期
bean的创建
整体流程
spring会扫描指定路径的的包,看包下面的每一个类,如果类上面有相关注解,spring就会帮你创建这个类的bean对象,经过依赖注入,初始化前,初始化,AOP,一系列流程创建对象,并管理bean的生命周期
流程总结:
- 扫描包(指定包路径)
- 推断构造方法
- 用构造方法实例化对象(单例bean,即所有getbean的哈希值相同)
- 依赖注入
- 初始化前
- 执行初始化方法
- 初始化后(AOP)
- 生成代理对象
- 得到bean
构造方法的选取
bean要帮你创建对象,依据就是类的构造方法,spring默认用无参构造方法,当只有一个有参构造方法,就用这个,如果有多个有参构造方法,就会报错,这时要手动指定某个构造方法为默认构造方法,就是在方法前加上 @AutoWrite
.
构造方法中参数的注入
入果参数传入的是对象,应该怎么注入?从spring对象池里找。
spring对象池可以理解为1个map,对象池里放这所有注册过的bean。找的时候先通过反射根据类型找,如果有多个 ,则根据参数名字去找
上面这个方法叫推断构造方法
AOP和代理对象
手写spring容器的思路
首先要实现一个根据类名
,获取对象的getbean
方法
如何获取到这些类
想想spring的实现方法,是通过在类上写一些注解
。Spring在扫描包的时候,通过这些注解,识别这些类,并
AOP
Sping Bean
Bean的创建
@SpringBootTest
class JavaallApplicationTests {
@Autowired
ApplicationContext applicationContext;
@Test
void isBeanSingleton() {
System.out.println(applicationContext.getBean("BeanTest"));
BeanTest beanTest1 = (BeanTest) applicationContext.getBean("BeanTest");
BeanTest beanTest2 = (BeanTest) applicationContext.getBean("BeanTest");
BeanTest beanTest3 = new BeanTest();
System.out.println("两个通过spring创建的bean:"+(beanTest1 == beanTest2));
System.out.println("两个通过spring创建的bean的成员对象:"+(beanTest1.getBeanContent() == beanTest2.getBeanContent()));
System.out.println("通过spring创建的bean和手动创建的对象:"+(beanTest1 == beanTest3));
System.out.println("通过spring创建的bean和手动创建的对象的成员对象:"+(beanTest1.getBeanContent() == beanTest3.getBeanContent()));
}
@Test
void testClone() throws IOException, ClassNotFoundException {
BeanTest beanTest1 = new BeanTest();
BeanTest beanTest2 = beanTest1.clone();
BeanTest beanTest3 = (BeanTest) beanTest1.deepClone();
System.out.println("浅拷贝的2个对象:"+(beanTest1 == beanTest2));
System.out.println("浅拷贝的2个对象的int:"+(beanTest1.getAge()== beanTest2.getAge()));
System.out.println("浅拷贝的2个对象的string:"+(beanTest1.getName()== beanTest2.getName()));
System.out.println("浅拷贝的2个对象成员对象:"+(beanTest1.getBeanContent()==beanTest2.getBeanContent()));
System.out.println("================================================================================");
System.out.println("浅拷贝的2个对象:"+(beanTest1 == beanTest3));
System.out.println("浅拷贝的2个对象的int:"+(beanTest1.getAge()== beanTest3.getAge()));
System.out.println("浅拷贝的2个对象的string:"+(beanTest1.getName()== beanTest3.getName()));
System.out.println("浅拷贝的2个对象成员对象:"+(beanTest1.getBeanContent()==beanTest3.getBeanContent()));
}
}
结果:
两个通过spring创建的bean:true
两个通过spring创建的bean的成员对象:true
通过spring创建的bean和手动创建的对象:false
通过spring创建的bean和手动创建的对象的成员对象:false
Bean的注册
beanDefinitionMap
SpringBoot帮助Spring解决了哪些问题
1.统一的依赖版本管理
在pom.xml
里点开
<artifactId>spring-boot-starter-parent</artifactId>
再点开里面的
<artifactId>spring-boot-dependencies</artifactId>
就可以看到
其对开发场景中常用框架的依赖文件做了统一版本号管理,所以被管理的这些依赖在
pom.xml
中引入是不需要写版本号
形如:
<artifactId>spring-boot-starter-xxx</artifactId>
就是官方提供的依赖启动器
即提供了官方认为
的开发者在该场景业务开发中
需要的依赖统一配置
2.自动配置
回忆ssm阶段,当我们想使用第三方依赖,如mybatis
,需要在xml中自己进行手动配置,把这个依赖交给spring管理
<!-- 配置整合mybatis -->
<!-- 1.关联数据库文件 -->
<context:property-placeholder location="classpath:database.properties"/>
<!-- 2.数据库连接池 -->
<!--数据库连接池
dbcp 半自动化操作 不能自动连接
c3p0 自动化操作(自动的加载配置文件 并且设置到对象里面)
-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<!-- 配置连接池属性 -->
<property name="driverClass" value="${jdbc.driver}"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="user" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<!-- c3p0连接池的私有属性 -->
<property name="maxPoolSize" value="30"/>
<property name="minPoolSize" value="10"/>
<!-- 关闭连接后不自动commit -->
<property name="autoCommitOnClose" value="false"/>
<!-- 获取连接超时时间 -->
<property name="checkoutTimeout" value="10000"/>
<!-- 当获取连接失败重试次数 -->
<property name="acquireRetryAttempts" value="2"/>
</bean>
<!-- 3.配置SqlSessionFactory对象 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 注入数据库连接池 -->
<property name="dataSource" ref="dataSource"/>
<!-- 配置MyBatis全局配置文件:mybatis-config.xml -->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
</bean>
可以想像,我们开发一个业务,需要的依赖很多,如果每一个都需要这么配置的话,将会使开发变的异常麻烦
于是对于这些依赖,spring官方将这些配置帮我们搞好了,无须我们再自己手写这些配置
我们只需要
对我们自己写的代码进行配置即可
3.由xml配置文件变为注解+ymal
注:springboot中仍然可以用xml配置,只是现在的开发习惯不用而已,并不是不能用
xml中仍然有许多重复的代码,springboot将配置方式再次简化,用注解实现类的注册
不水群,偷偷卷被我抓到了吧
狗哥,这是把自己的屯的几个月的文件都贴上来了吗