目录
10、Beanfactory和 Application contexts 有什么区别?
15、注解装配(@Required 注解、@Autowired 注解、@Qualifier 注解)
1、spring的原理结构
aop技术
Spring中AOP技术是设计模式中的动态代理模式。只需实现jdk提供的动态代理接口InvocationHandler,所有被代理对象的方法都由InvocationHandler接管实际的处理任务。
9、什么是控制反转(ioc),别名依赖注入
Spring中IOC则利用了Java强大的反射机制来实现。所谓依赖注入即组件之间的依赖关系由容器在运行期决定。其中依赖注入的方法有两种,通过构造函数注入,通过set方法进行注入。
9、什么是Spring IOC 容器?
Spring IOC 容器管理bean对象的整个生命周期。其底层通过concurrenthashmap来存放bean。
10、Beanfactory和 Application contexts 有什么区别?
BeanFactory:
是Spring里面最低层的接口,提供了最简单的容器的功能,只提供了实例化对象和拿对象的功能;
BeanFactory在启动的时候不会去实例化Bean,中有从容器中拿Bean的时候才会去实例化;
ApplicationContext:
应用上下文,继承BeanFactory接口,它是Spring的一各更高级的容器
ApplicationContext在启动的时候就把所有的Bean全部实例化了。
具体实现(ClassPathXmlApplicationContext)
12、解释Spring支持的几种bean的作用域
Spring框架支持以下五种bean的作用域:
-
singleton : bean在每个Spring ioc 容器中只有一个实例(默认)。
-
prototype:一个bean的定义可以有多个实例。
-
request:每次http请求都会创建一个bean,该作用域仅在基于web的Spring ApplicationContext情形下有效。
-
session:在一个HTTP Session中,一个bean定义对应一个实例。该作用域仅在基于web的Spring ApplicationContext情形下有效。
-
global-session:在一个全局的HTTP Session中,一个bean定义对应一个实例。该作用域仅在基于web的Spring ApplicationContext情形下有效。
13、Spring框架中的单例bean是线程安全的吗?
不,Spring框架中的单例bean不是线程安全的。但是bean基本上都是用来实现依赖注入,不存在修改操作,所以相对来说不存在线程不安全问题。
为什么bean是单例的?
只在初始化的时候实例化一次,提高效率;
减少了内存开销
14、bean的生命周期
对象的生命周期:创建(实例化-初始化)-使用-销毁,Spring提供了许多对外接口,允许开发者对这三个过程(实例化、初始化、销毁)的前后做一些操作。
在Spring Bean中,实例化是为bean对象开辟空间(具体可以理解为构造函数的调用),初始化则是对属性的初始化,也就是属性注入(构造函数也可以有属性的初始化语句,但不属于这一部分),而属性注入是通过setter方法注入属性(不管是注解方式还是bean配置property属性方式,其实质都是通过属性的setter方法实现的)。
15、注解装配(@Required 注解、@Autowired 注解、@Qualifier 注解)
@Required 注解:指定具体的bean的id(byname),进行装配注入
@Autowired 注解:根据类型自动装配(bytype)
@Qualifier 注解:与@Autowired 注解一同使用,避免混淆的bean
16、spring中bean解决循环依赖
依赖注入稍不注意就会出现循环依赖:
Bean之间的依赖顺序: BeanA -> BeanB -> BeanA
举个例子:
@Component
public class CircularDependencyA {
private CircularDependencyB circB;
@Autowired
public CircularDependencyA(CircularDependencyB circB) {
this.circB = circB;
}
}
@Component
public class CircularDependencyB {
private CircularDependencyA circA;
@Autowired
public CircularDependencyB(CircularDependencyA circA) {
this.circA = circA;
}
}
运行SpringBootApplication:
@SpringBootApplication
@ComponentScan("com.example.circulardependency.constructor")
public class CirculardependencyApplication {
public static void main(String[] args) {
SpringApplication.run(CirculardependencyApplication.class, args);
}
}
报错
BeanCurrentlyInCreationException: Error creating bean with name 'circularDependencyA': Requested bean is currently in creation: Is there an unresolvable circular reference?
解决办法
出现循环依赖是因为设计问题,最佳处理方法是重新设计。
在实际开发中,推倒重来往往是不允许的,所以会有以下几种补救方法。
与constructor注入不同,setter
是按需注入的,并且允许依赖对象为null;
@Component
public class CircularDependencyA {
private CircularDependencyB circB;
@Autowired
public void setCircB(CircularDependencyB circB) {
this.circB = circB;
}
public CircularDependencyB getCircB() {
return circB;
}
}
@Component
public class CircularDependencyB {
private CircularDependencyA circA;
private String message = "Hi!";
@Autowired
public void setCircA(CircularDependencyA circA) {
this.circA = circA;
}
public String getMessage() {
return message;
}
}
添加单元测试:
@RunWith(SpringRunner.class)
@SpringBootTest
@ComponentScan("com.example.circulardependency.setter")
public class CirculardependencyApplicationTests {
@Bean
public CircularDependencyB getDependencyB() {
return new CircularDependencyB();
}
@Bean
public CircularDependencyA getDependencyA() {
CircularDependencyA circularDependencyA = new CircularDependencyA();
circularDependencyA.setCircularDependencyB(getDependencyB());
return circularDependencyA;
}
@Test
public void contextLoads() {
System.out.println("Hello world.");
CircularDependencyA circularDependencyA = getDependencyA();
System.out.println(circularDependencyA.getCircularDependencyB().getMessage());
}
}
2. @Lazy注解
@Lazy
延迟初始化。在本例中,会先构建 CircularDependencyA完成后, 再构建CircularDependencyB,打破dependency circle。
@Component
public class CircularDependencyA {
private CircularDependencyB circB;
@Autowired
public CircularDependencyA(@Lazy CircularDependencyB circB) {
this.circB = circB;
}
}
3. 使用ApplicationContextAware, InitializingBean
ApplicationContextAware获取SpringContext,用于加载bean;InitializingBean定义了设置Bean的property之后的动作。
@Component
public class CircularDependencyA implements InitializingBean, ApplicationContextAware {
private CircularDependencyB circB;
private ApplicationContext context;
@Override
public void afterPropertiesSet() throws Exception {
this.circB = context.getBean(CircularDependencyB.class);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.context = applicationContext;
}
public CircularDependencyB getCircularDependencyB() {
return circB;
}
}
原理:跟Spring Bean的Life cycle有关:先实例化,再调用setApplicationContext(), afterPropertiesSet(); 所以,CircularDependencyB已经加载完毕后,再加载CircularDependencyA。
倘若,CircularDependencyA先实例化, 调用afterPropertiesSet()时发现CircularDependencyB尚未加载,先加载CircularDependencyB(调用构造函数,由于此时CircularDependencyA已经实例化了,所以能够顺利加载),设置属性circB,CircularDependencyA加载完成。
17、Spring的MVC框架
处理前台与后台数据页面请求