Java面试——SSM基础知识:Spring框架、Spring MVC、MyBatis…
1 String框架
1.1 IOC和DI
- 控制反转(IOC):Spring容器使用工厂模式来创建所需要的对象,使得不需要自己去创建,直接调用Spring提供的对象即可。
- 依赖注入(DI):Spring使用Java Bean对象的setter方法或者带参数的构造方法,在创建所需对象时将其属性自动设为所需要的值。
- 构造器依赖注入:容器触发一个类的构造器。该类有一系列参数,每个参数代表一个对其他类的依赖。
- Setter方法注入:容器通过调用无参构造器或无参static工厂方法实例化bean之后,调用该bean的setter方法。
1.2 Bean
1.2.1 作用域
Spring框架支持以下五种bean的作用域:
- singleton:bean在每个Spring IOC容器中只有一个实例。
- prototype:一个bean的定义可以有多个实例。
- request:每次http请求都会创建一个bean,该作用域仅在基于web的Spring ApplicationContext情形下有效。
- session:在一个HTTP Session中,一个bean定义对应一个实例。该作用域仅在基于web的Spring ApplicationContext情形下有效。
- application:属于应用程序域。应用程序启动时bean创建,应用程序销毁时bean 销毁。该作用域仅在基于web的ServletContext。
1.2.2 自动装配模式
Spring的自动装配功能:无须在Spring配置文件中描述Java Bean之间的依赖关系(如配置<property>
、<constructor-arg>
)。
自动装配模式:
- no:Spring框架的默认设置,在该设置下自动装配关闭。开发者需要自行在bean定义中用标签明确的设置依赖关系 。
- byName:该选项可根据bean名称设置依赖关系 。 当向一个bean中自动装配一个属性时,容器将根据bean的名称自动在在配置文件中查询一个匹配的bean。 若找到则装配这个属性,若没找到则报错。
- byType:该选项可以根据bean类型设置依赖关系 。 当向一个bean中自动装配一个属性时,容器将根据 bean的类型自动在在配置文件中查询一个匹配的bean。 若找到则装配这个属性,若没找到则报错。
- constructor:构造器的自动装配和byType模式类似,但仅适用于与有构造器相同参数的bean。若在容器中没有找到与构造器参数类型一致的bean,则会抛出异常 。
- default:该模式自动探测使用构造器自动装配或byType自动装配。 首先会尝试找合适的带参数的构造器,若找到则用构造器自动装配;若在bean内部没有找到相应的构造器或无参构造器,容器就会自动选择byType自动装配方式 。
【例】如下注入
可以改造为
1.2.3 生命周期
1.2.3.1 doGetBean()源码
Spring框架在创建的bean时都会调用AbstractBeanFactory类中的doGetBean()
方法。
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
// 获取beanName。有三种形式:原始的beanName、加了&、别名
final String beanName = transformedBeanName(name);
Object bean;
// Eagerly check singleton cache for manually registered singletons.
// 是否已经创建了
Object sharedInstance = getSingleton(beanName);
// 已经创建了——若没有构造参数,进入该方法;如果有构造参数,往else走,即不获取bean,而直接创建bean
if (sharedInstance != null && args == null) {
if (logger.isTraceEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
} else {
logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
}
}
// 若为普通bean,直接返回;若为FactoryBean,返回其getObject
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
} else {
// Fail if we're already creating this bean instance:
// We're assumably within a circular reference.
// 没创建过bean或者是多例的情况或者有参数的情况
// 创建过Prototype的bean会循环引用。需抛出异常,单例才尝试解决循环依赖的问题
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
// Check if bean definition exists in this factory.
BeanFactory parentBeanFactory = getParentBeanFactory();
// 父容器存在,本地没有当前beanName,从父容器取
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// Not found -> check parent.
// 处理后,如果是加&,就补上&
String nameToLookup = originalBeanName(name);
if (parentBeanFactory instanceof AbstractBeanFactory) {
return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
nameToLookup, requiredType, args, typeCheckOnly);
} else if (args != null) {
// Delegation to parent with explicit args.
return (T) parentBeanFactory.getBean(nameToLookup, args);
} else if (requiredType != null) {
// No args -> delegate to standard getBean method.
return parentBeanFactory.getBean(nameToLookup, requiredType);
} else {
return (T) parentBeanFactory.getBean(nameToLookup);
}
}
if (!typeCheckOnly) {
// typeCheckOnly为false,将beanName放入alreadyCreated中
markBeanAsCreated(beanName);
}
try {
// 获取BeanDefinition
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
// 抽象类检查
checkMergedBeanDefinition(mbd, beanName, args);
// Guarantee initialization of beans that the current bean depends on.
// 如果有依赖的情况,先初始化依赖的bean
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dep : dependsOn) {
// 检查是否循环依赖,a依赖b,b依赖a。包括传递的依赖,比如a依赖b,b依赖c,c依赖a
if (isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
// 注册依赖关系
registerDependentBean(dep, beanName);
try {
// 初始化依赖的bean
getBean(dep);
} catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName