1.Spring 中,有两个 id 相同的 bean,会报错吗,如果会报错,在哪个阶段报错?
首先,在同一个XML配置文件里面,不能存在id相同的两个bean,否则spring容器启动的时候会报错。
因为id这个属性表示一个Bean的唯一标志符号,所以Spring在启动的时候会去验证id的唯一性,一旦发现重复就会报错,
这个错误发生Spring对XML文件进行解析转化为BeanDefinition的阶段。
但是在两个不同的Spring配置文件里面,可以存在id相同的两个bean。 IOC容器在加载Bean的时候,默认会多个相同id的bean进行覆盖。
在Spring3.x版本以后,这个问题发生了变化
我们知道Spring3.x里面提供@Configuration注解去声明一个配置类,然后使用@Bean注解实现Bean的声明,这种方式完全取代了XMl。
在这种情况下,如果我们在同一个配置类里面声明多个相同名字的bean,在Spring IOC容器中只会注册第一个声明的Bean的实例。
后续重复名字的Bean就不会再注册了。
存储时使用beanName作为key,内容作为value存储在Map中。流程:没有得时候进行实例化bean,存在场景下获取一下map,不在进行bean生命周期创建。
2.Spring ioc
spring得ioc机制和aop机制算是核心,在面试过程中还是含含糊糊,特此整理。
IOC全名inversion of controller 控制反转,
控制反转如何理解?
主要是 bean 的创建、管理的权利,控制 bean 的整个生命周期。把这个权利交给了 Spring 容器,而不是自己去控制,就是反转。由之前的自己主动创建对象,变成现在被动接收别人给我们的对象的过程,这就是反转。
这样做得好处是什么?
降低了业务对象之间的复杂性,让组件之间互相解耦
ioc最重要得就是容器, 那么 Spring 如何设计容器的呢?
使用 ApplicationContext
,它是 BeanFactory
的子类,更好的补充并实现了 BeanFactory
的。
BeanFactory
简单粗暴,可以理解为 HashMap:
-
Key - bean name
-
Value - bean object
但它一般只有 get, put 两个功能,所以称之为“低级容器”。
而 ApplicationContext
多了很多功能,因为它继承了多个接口,可称之为“高级容器”。在下文的搭建项目中,我们会使用它。
控制反转是通过依赖注入实现的,依赖倒置原则(即程序不应依赖于实现,而应依赖于抽象)是IoC的设计原理,依赖注入是IoC的实现方式。
通常我们所使用得xml,注解都是通过依赖注入这种进行实现得。
3.FactoryBean和BeanFactory得区别?
BeanFactory的代码如下:
public interface BeanFactory {
String FACTORY_BEAN_PREFIX = "&";
Object getBean(String var1) throws BeansException;
<T> T getBean(String var1, Class<T> var2) throws BeansException;
Object getBean(String var1, Object... var2) throws BeansException;
<T> T getBean(Class<T> var1) throws BeansException;
<T> T getBean(Class<T> var1, Object... var2) throws BeansException;
<T> ObjectProvider<T> getBeanProvider(Class<T> var1);
<T> ObjectProvider<T> getBeanProvider(ResolvableType var1);
boolean containsBean(String var1);
boolean isSingleton(String var1) throws NoSuchBeanDefinitionException;
boolean isPrototype(String var1) throws NoSuchBeanDefinitionException;
boolean isTypeMatch(String var1, ResolvableType var2) throws NoSuchBeanDefinitionException;
boolean isTypeMatch(String var1, Class<?> var2) throws NoSuchBeanDefinitionException;
@Nullable
Class<?> getType(String var1) throws NoSuchBeanDefinitionException;
@Nullable
Class<?> getType(String var1, boolean var2) throws NoSuchBeanDefinitionException;
String[] getAliases(String var1);
}
FactoryBean的代码如下:
public interface FactoryBean<T> {
String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";
@Nullable
T getObject() throws Exception;
@Nullable
Class<?> getObjectType();
default boolean isSingleton() {
return true;
}
}
3.1区别
1.作用不同
BeanFactory是Spring框架的基础设施,是IOC容器,它是用于管理bean的工厂容器。BeanFactory加载配置文件时不会初始化bean,而是在获取bean的时候才会初始化bean,而是在获取bean的实惠才会去实例化对象。BeanFactory只提供了基础的功能,如获取bean、检测bean、管理bean的生命周期等。
FactoryBean是一个bean,可以实现自己的逻辑去创建其他bean对象,是一个专门的工厂。FactoryBean的作用是在BeanFactory或者ApplicationContext获取其他bean之前进行额外的处理,例如:在获取某个bean之前需要进行一些特殊的计算或者加工操作。
2.返回值不同
BeanFactory获取的是bean的实例对象
FactoryBean获取的是FactoryBean本身的实例对象,也就是调用FactoryBean#getObject()方法后返回的对象。需要通过FactoryBean#getObject()方法获取FactoryBean中创建出来的bean实例对象。
3.配置不同
BeanFactory配置只需要在XML文件定义即可,可以通过ClassPathXmlApplicationContext、FileSystemXmlApplicationContext等来加载运行时资源。
FactoryBean配置时应当将自定义工厂定义为Spring容器中的一个普通bean,并且在该对象上指定FactoryBean的实现类路径,由Spring容器创建并管理。
4.生命周期不同
BeanFactory和ApplicationContext在容器启动时都会将所有单例bean预先实例化。当从BeanFactory中获取单例bean时,它们才会被实例化并放入BeanFactory中,这就意味着在使用者第一次调用之前,它们是不存在的。因此,BeanFactory对象只会一次性调用所有bean的初始化方法。
FactoryBean可以实现Bean的生命周期接口,从而改变Bean的初始化和销毁过程。
总结:如果只是想获取单例的bean对象,可以使用BeanFactory;如果需要在获取单例的bean前或根据不同情况获取不同的实例化对象,则需要使用FactoryBean。
4.Spring Aop
aop(Aspect Orient Programming)面向切面编程。作为面向对象得补充。
用于处理系统中分布于各个模块的横切关注点,比如事务管理、日志、缓存等等。AOP实现的关键在于AOP框架自动创建的AOP代理,AOP代理主要分为静态代理和动态代理,静态代理的代表为AspectJ;而动态代理则以Spring AOP为代表。
目的:代码解耦,代码复用,并有利于可操作性和可维护性。
核心思想:对目标对象得增强。
Spring AOP使用的动态代理,所谓的动态代理就是说AOP框架不会去修改字节码,而是在内存中临时为方法生成一个AOP对象,这个AOP对象包含了目标对象的全部方法,并且在特定的切点做了增强处理,并回调原对象的方法。
Spring AOP中的动态代理主要有两种方式,JDK动态代理(用于接口类)和CGLIB动态代理(不是接口类)。
JDK动态代理通过反射来接收被代理的类,并且要求被代理的类必须实现一个接口。JDK动态代理的核心是InvocationHandler接口(Invocation翻译成调用,即调用handler)和Proxy类。
Proxy.newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)
5.spring bean加载过程?
面试回答:spring 得bean加载过程分为2步,实例化和初始化,销毁。
实例化:在堆空间申请一块内存,默认得属性值都是默认值(防止内存再分配)
初始化:
(1)属性赋值 1.如果bean得属性有@Autowired要注入得属性,则会进行属性填充
2.进行属性填充的前提是要保证属性实例已经存在spring容器中,如果不存在会去先加载属性
(2)调用执行aware接口的方法 调用invokeAwareMethods方法:2.1 实现BeanNameAware接口调用setBeanName方法 2.2实现BeanClassLoaderAware接口,调用setBeanClassLoader方法 2.3实现BeanFactoryAware接口实现setBeanFactory方法。(aware接口是可识别的,可意识的,让bean意识到有spring的存在)
(3)执行BeanPostProcessor的前置方法 (Processor代表处理器的意思)
(4)执行init-method方法
(5)执行BeanPostProcessor的后置方法
6.bean扩展点?
1.实现Aware接口 实现BeanNameAware接口的setBeanName方法
实现BeanClassLoaderAware接口的setClassLoader方法
实现BeanFactoryAware接口的setBeanFactory方法
2.实现InitializingBean
和 DisposableBean
接口
如果要在 Bean 初始化时添加自定义逻辑,可以实现 InitializingBean
接口。实现afterPropertiesSet方法
如果要在 Bean 销毁时添加自定义逻辑,可以实现 DisposableBean
接口。实现destory方法
或者使用init-method注解,实现init方法和destory方法。
3.实现BeanPostProcessor接口,实现postProcessBeaforeInitialization方法和postProcessAfterInitialization方法
7.SpringMVC请求处理过程?