1.IOC和DI区别?
IOC: 控制反转,将类的对象的创建交给Spring类管理创建.
DI: 依赖注入,将类里面的属性在创建类的过程中给属性赋值.
DI和IOC的关系: DI不能单独存在,DI需要在IOC的基础上来完成.
2.Spring的循环依赖的解决?
spring进行扫描->反射后封装成beanDefinition对象->放入beanDefinitionMap->遍历map->验证(是否单例、是否延迟加载、是否抽象)->推断构造方法->准备开始进行实例->去单例池中查,没有->去二级缓存中找,没有提前暴露->生成一个objectFactory对象暴露到二级缓存中->属性注入,发现依赖Y->此时Y开始它的生命周期直到属性注入,发现依赖X->X又走一遍生命周期,当走到去二级缓存中找的时候找到了->往Y中注入X的objectFactory对象->完成循环依赖。
1、为什么要使用X的objectFacory对象而不是直接使用X对象?
利于拓展,程序员可以通过beanPostProcess接口操作objectFactory对象生成自己想要的对象
2、是不是只能支持单例(scope=singleton)而不支持原型(scope=prototype)?
是。因为单例是spring在启动时进行bean加载放入单例池中,在依赖的bean开始生命周期后,可以直接从二级缓存中取到它所依赖的bean的objectFactory对象从而结束循环依赖。而原型只有在用到时才会走生命周期流程,但是原型不存在一个已经实例化好的bean,所以会无限的创建->依赖->创建->依赖->…。
3、循环依赖是不是只支持非构造方法?
是。类似死锁问题
3.Spring的AOP的理解?
Spring AOP就是面向对象的一种补充
利用切面的技术,去匹配拥有相同的方法所有的类,对这些方法实现增强处理(不改变源码)
4.谈谈事务的传播行为?
PROPAGATION_REQUIRED:如果当前没有事务,就创建一个新事务,如果当前存在事务,就加入该事务,这是最常见的选择,也是Spring默认的事务传播行为。(required需要,没有新建,有加入)
PROPAGATION_SUPPORTS:支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就以非事务执行。(supports支持,有则加入,没有就不管了,非事务运行)
PROPAGATION_MANDATORY:支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就抛出异常。(mandatory强制性,有则加入,没有异常)
PROPAGATION_REQUIRES_NEW:创建新事务,无论当前存不存在事务,都创建新事务。(requires_new需要新的,不管有没有,直接创建新事务)
PROPAGATION_NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。(not supported不支持事务,存在就挂起)
PROPAGATION_NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。(never不支持事务,存在就异常)
PROPAGATION_NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则按REQUIRED属性执行。(nested存在就在嵌套的执行,没有就找是否存在外面的事务,有则加入,没有则新建)
PROPAGATION_NEVER
总是非事务地执行,如果存在一个活动事务,则抛出异常。
5.Spring的常用注解并解释作用?
@Controller(肯除lei儿)
用法:标记于一个类上面
作用:用来注解这个bean(类)是MVC模型中的一个控制层,使分发处理器识别到该类,该类会被spring的auto-scan扫到纳入管理。通俗来,被这个标注类里面的方法加上@RequestMaping(“…”),就可以直接被浏览器调用然后做一些数据逻辑处理。
实例解释:如果要在浏览器访问Action类中的carRun方法(本地)127.0.0.1:8080/car/carRun
@Request(瑞快死)Maping
用法:1.标记于一个被@Controller标注的类上
2.标记于被@Controller标注类里面的方法上面
作用:用法1,表示该被标注类下面所有方法的父类标注(可以理解为所有用法2“继承”用法1)@RequestMaping有六个属性value、method、consumes、produces、params、headers
value:指定浏览器请求的地址;
method:指定请求的method类型, GET、POST、PUT、DELETE等;
consumes:指定处理请求的提交内容类型(Content-Type),例如application/json, text/html;
produces:指定返回的内容类型,仅当request请求头中的(Accept)类型中包含该指定类型才返回;
params:指定request中必须包含某些参数值是,才让该方法处理;
headers:指定request中必须包含某些指定的header值,才能让该方法处理请求;
实例解释:如果要在浏览器访问Action类中的carRun方法,只需要本地域名+端口号+该标注所定义的value值即可(127.0.0.1:8080/car/carRun)
@RequestMaping常用的记住value和method,
@Service
用法:用于标注业务层组件(Service层)上
作用:标注于业务层组件上表示定义一个bean,自动根据所标注的组件名称实例化一个首字母为小写的bean。
实例解释:IocCarService类被标注为一个bean,bean名称为iocCarService,此时该类已经被spring纳入管理中,待使用
@Resource(瑞sao斯)
用法:标注于字段上或者setter方法上,@Resource默认按ByName进行自动装配
作用:用来自动装配Bean,激活一个命名资源的依赖注入。@Resource属性name可以定义被自动装配Bean的名称
实例解释:在IocCarService类中IIocCarDao 的实现类已经被@Repository标注为一个被Spring管理的Bean,此时需要用到它的时候只需要在属性名称上标注@Resource用户自动装配就可以了。
@Autowired(奥特为儿)
@Repository(瑞泡死特瑞)
用法:用户标注数据访问层组件(Dao层)
作用:实现Dao访问;将类识别为Bean,同时它将所标注的类中抛出的数据访问异常封装为 Spring 的数据访问异常类型。
实例解释:Dao层实现类IIocCarDaoImpl 被Spring装载为bean纳入管理中,bean名称为iIocCarDaoImpl。 同时它将所标注的类中抛出的数据访问异常封装为 Spring 的数据访问异常类型。
@Component(抗抛嫩特)
用法:泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注。
作用:和前面@Service、@Repository、@Controller一样,只是它们比@Component更巨细化。
6. Spring Bean 的生命周期
Bean 生命周期的整个执行过程描述如下:
(1) 根据配置情况调用 Bean 构造方法或工厂方法实例化 Bean。
(2) 利用依赖注入完成 Bean 中所有属性值的配置注入。
(3) 如果 Bean 实现了 BeanNameAware 接口,则 Spring 调用 Bean 的 setBeanName() 方法传入当前 Bean 的 id 值。
(4) 如果 Bean 实现了 BeanFactoryAware 接口,则 Spring 调用 setBeanFactory() 方法传入当前工厂实例的引用。
(5) 如果 Bean 实现了 ApplicationContextAware 接口,则 Spring 调用 setApplicationContext() 方法传入当前 ApplicationContext 实例的引用。
(6) 如果 BeanPostProcessor(破色思) 和 Bean 关联,则 Spring 将调用该接口的预初始化方法 postProcessBeforeInitialzation() 对 Bean 进行加工操作,此处非常重要,Spring 的 AOP 就是利用它实现的。
(7) 如果 Bean 实现了 InitializingBean 接口,则 Spring 将调用 afterPropertiesSet() 方法。初始化 bean的时候执行,可以针对某个具体的bean进行配置。afterPropertiesSet 必须实现 InitializingBean接口。实现 InitializingBean接口必须实现afterPropertiesSet方法。
(8) 如果在配置文件中通过 init-method 属性指定了初始化方法,则调用该初始化方法。
(9) 如果 BeanPostProcessor 和 Bean 关联,则 Spring 将调用该接口的初始化方法 postProcessAfterInitialization()。此时,Bean 已经可以被应用系统使用了。
(10) 如果在 中指定了该 Bean 的作用范围为 scope=“singleton”,则将该 Bean 放入 Spring IoC 的缓存池中,将触发 Spring 对该 Bean 的生命周期管理;如果在 中指定了该 Bean 的作用范围为 scope=“prototype”,则将该 Bean 交给调用者,调用者管理该 Bean 的生命周期,Spring 不再管理该 Bean。
(11) 如果 Bean 实现了 DisposableBean 接口,则 Spring 会调用 destory() 方法将 Spring 中的 Bean 销毁;如果在配置文件中通过 destory-method 属性指定了 Bean 的销毁方法,则 Spring 将调用该方法对 Bean 进行销毁。
[
](https://blog.csdn.net/haohaoxuexiyai/article/details/109747666)
7.spring创建Bean的几种方式
1. 使用XML文件进行创建
<bean id="xxxx" class="xxxx.xxxx"/>
2. 使用注解
用@Component,@Service,@Controller,@Repository注解
这几个注解都是同样的功能,被注解的类将会被Spring 容器创建单例对象。
@Component : 侧重于通用的Bean类
@Service:标识该类用于业务逻辑
@Controller:标识该类为Spring MVC的控制器类
@Repository: 标识该类是一个实体类,只有属性和Setter,Getter
@Component
public class User{
}
当用于Spring Boot应用时,被注解的类必须在启动类的根路径或者子路径下,否则不会生效。
如果不在,可以使用@ComponentScan标注扫描的路径。
spring xml 也有相关的标签
@ComponentScan(value={"com.microblog.blog","com.microblog.common"})
public class MicroblogBlogApplication {
public static void main(String args[]){
SpringApplication.run(MicroblogBlogApplication.class,args);
}
}
3. 使用@Bean注解,这个用在SpringBoot中
@Configuration 标识这是一个Spring Boot 配置类,其将会扫描 该类中是否存在@Bean 注解的方法,比如如下代码,将会创建 User对象并放入容器中。
@ConditionalOnBean 用于判断存在某个Bean时才会创建User Bean.
这里创建的Bean名称默认为方法的名称user。也可以 @Bean(“xxxx”)定义。
@Configuration
public class UserConfiguration{
@Bean
@ConditionalOnBean(Location.class)
public User user(){
return new User();
}
}
4. 使用注解@Import,也会创建对象并注入容器中
@Import(User.class)
public class MicroblogUserWebApplication {
public static void main(String args[]) {
SpringApplication.run(MicroblogUserWebApplication.class, args);
}
}
5.使用ImportSelector或者ImportBeanDefinitionRegistrar接口,配合@Import实现。
在使用一些Spring Boot第三方组件时,经常会看到@EnableXXX来使能相关的服务,这里以一个例子来实现。
创建测试类
@Slf4j
public class House {
public void run(){
log.info("House run ....");
}
}
@Slf4j
public class User {
public void run(){
log.info("User run ....");
}
}
@Slf4j
public class Student {
public void run(){
log.info("Student run ....");
}
}
实现ImportSelector接口
selectImports方法的返回值为需要创建Bean的类名称。这里创建User类。
@Slf4j
public class MyImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
log.info("MyImportSelector selectImports ...");
return new String[]{
User.class.getName()};
}
}
实现ImportBeanDefinitionRegistrar接口
beanDefinitionRegistry.registerBeanDefinition用于设置需要创建Bean的类名称。这里创建House类。
@Slf4j
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) {
log.info("MyImportBeanDefinitionRegistrar registerBeanDefinitions .....");
BeanDefinition beanDefinition = new RootBeanDefinition(House.class.getName());
beanDefinitionRegistry.registerBeanDefinition(House.class.getName(),beanDefinition);
}
}
创建一个配置类
这里创建Student类。
@Configuration
public class ImportAutoconfiguration {
@Bean
public Student student(){
return new Student();
}
}
创建EnableImportSelector注解
EnableImportSelector注解上使用@Import,引入以上的三个类。
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Target(ElementType.TYPE)
@Import({MyImportSelector.class,ImportAutoconfiguration.class,MyImportBeanDefinitionRegistrar.class})
public @interface EnableImportSelector {
String value();
}
测试
@EnableImportSelector(value = "xxx")
@SpringBootApplication
public class ImportDemoApplication {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(ImportDemoApplication.class, args);
User user = context.getBean(User.class);
user.run();
Student student = context.getBean(Student.class);
student.run();
House house = context.getBean(House.class);
house.run();
}
}
输出,可以看到,三个类User Student House都创建成功,都可从Spring 容器中获取到。
2019-06-20 17:53:39.528 INFO 27255 --- [ main] com.springboot.importselector.pojo.User : User run ....
2019-06-20 17:53:39.530 INFO 27255 --- [ main] c.s.importselector.pojo.Student : Student run ....
2019-06-20 17:53:39.531 INFO 27255 --- [ main] c.springboot.importselector.pojo.House : House run ....
8. IOC的3种注入方式
接口注入:
接口注入模式因为历史较为悠久,在很多容器中都已经得到应用。但由于其在灵活性、易用性上不如其他两种注入模式,因而在 IOC的专题世界内并不被看好。
Setter 注入:
对于习惯了传统 javabean 开发的程序员,通过 setter 方法设定依赖关系更加直观。
如果依赖关系较为复杂,那么构造子注入模式的构造函数也会相当庞大,而此时设值注入模式则更为简洁。
如果用到了第三方类库,可能要求我们的组件提供一个默认的构造函数,此时构造子注入模式也不适用。
构造器注入:
在构造期间完成一个完整的、合法的对象。
所有依赖关系在构造函数中集中呈现。
依赖关系在构造时由容器一次性设定,组件被创建之后一直处于相对“不变”的稳定状态。
只有组件的创建者关心其内部依赖关系,对调用者而言,该依赖关系处于“黑盒”之中。
9. Spring Bean的生命周期
Bean生命周期一般有下面的四个阶段:
- Bean的定义
- Bean的初始化
- Bean的生存期
- Bean的销毁
生命周期