1.解释一下什么是 ioc?
IOC可以叫做控制反转,还可以称为依赖注入。原本程序需要用个某个类的功能时需要在程序中构建该对象,而使用IOC,需要用的类会放在spring容器中,该类的构建操作由spring容器完成,但类需要使用到该类时,容器才会把它注入到程序中。IOC降低了程序之间的耦合度。
2.spring 常用的注入方式有哪些?
- 构造方法注入 <constructor-arg>
- setter注入 <property>
- 基于注解注入
3. BeanFactory和FactoryBean的区别?
- BeanFactory是一个工厂类接口,负责生产和管理bean的一个工厂。
- FactoryBean也是接口,为IOC容器中Bean的实现提供了更加灵活的方式,FactoryBean在IOC容器的基础上给Bean的实现加上了一个简单工厂模式和装饰者模式。
4.Spring Bean生命周期?
- Spring对Bean进行初始化(new)
- 按照Spring上下文对实例化的Bean进行IOC注入(比如set方法注入)
- 如果Bean实现了BeanNameAware接口,Spring将Bean的ID传递给setBeanName方法(主要是为了通过Bean的引用来获取Bean的ID)
- 如果Bean实现了BeanFactoryAware接口,会调用setBeanFactory方法,传递的是BeanFactory容器。(这样可以获取其他Bean)
- 如果Bean实现了ApplicationContextAwaer接口,Spring容器将调用setApplicationContext(ApplicationContext ctx)方法,把应用上下文作为参数传入。(作用与BeanFactory类似都是为了获取Spirng容器,不同的是Spring容器在调用setApplicationContext方法时会把它自己作为参数传入,而Spring容器在调用setBeanFactory前需要指定参数,但ApplicationContent是BeanFactory的子接口,有更多的实现方法)
- 如果Bean关联了BeanPostProcessor接口,Spring将调用postProcessBeforeInitialization方法。(作用是在Bean实例创建成功后对其进行增强处理,如对Bean进行修改,增加某个功能)
- 如果Bean实现了InitializingBean接口,Spring会调用afterPropertiesSet方法和init-method方法,都是对Bean的全部属性设置成功后执行的初始化方法。
- 如果Bean关联了BeanPostProcess接口,Spring将调用postProcessAfterInitialization方法(与之前方法调用一样,这里由于是在Bean初始化结束时调用After方法,也可用于缓存技术)
- 当Bean不再需要时,如果Bean实现了DisposableBean接口,会调用destory()方法。
- 最后如果设置了 destroy-method属性,会自动调用配置的方法。
5. Spring AOP
AOP的代理主要分为静态代理和动态代理。静态代理主要是AspectJ;动态代理以Spring AOP为代表。
5.1 AspectJ
AspectJ是静态代理的增强,所谓静态代理,就是AOP框架会在编译阶段生成AOP代理类,因此也称为编译时增强,会在编译阶段将AspectJ织入到Java字节码中,运行的时候就是增强之后的AOP对象。
5.2 动态代理
所谓的动态代理就是说AOP框架不会去修改字节码,而是每次运行时在内存中临时为方法生成一个AOP对象,这个AOP对象包含了目标对象的全部方法,并且在特定的切点做了增强处理,并回调原对象的方法。
5.2.1 JDK动态代理
JDK动态代理只提供接口的代理,不支持类的代理。核心InvocationHandler接口和Proxy类,InvocationHandler通过invoke()方法反射来调用目标类中代码,动态地将横切逻辑和业务编织在一起;接着,Proxy利用InvocationHandler动态创建一个符合某一接口的实例,生成目标类的代理对象。
5.2.2 CGLIB动态代理
如果代理类没有实现InvocationHandler接口,那么SpringAOP会选择使用CGLIB来动态代理目标类。CGLIB(Code Generation Library),是一个代码生成的类库,可以在运行时动态的生成指定类的一个子类对象,并覆盖其中特定方法并添加增强代码,从而实现AOP。CGLIB是通过继承的方式做的动态代理,因此如果某个类被标记为final,那么它是无法使用CGLIB做动态代理的。
5.2.3 JDK和CGLIB的使用场景?
- JDK只能代理实现了接口的类。适合程序需要频繁、反复地创建代理对象。
- CGLIB不能代理final类,可以代理没有实现接口的对象,适合不需要频繁创建代理对象的应用,如单例Bean。
5.2.4 JDK动态代理和CGLIB的区别?
- JDK动态代理只能对实现了接口的类生成代理,而不能针对类。
- CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法实现增强。
6. Spring框架中使用到的设计模式?
- 工厂模式:BeanFactory就是简单工厂模式的体现。
- 单例模式:Bean默认为单例模式。
- 代理模式:SpringAOP功能用到JDK的动态代理。
- 模板方法:RestTemplate,JpaTemplate.
- 观察者模式:Spring中listener的实现——ApplicationListener
7.Spring Bean的作用域?
- Singleton:每个IOC容器仅有一个实例。
- Prototype:每次请求都会生成一个新的实例。
- Request:每一次HTTP请求都会产生一个新的实例,并且该bean仅在当前HTTP请求有效。
- Session:每依次HTTP请求都会产生一个新的实例,并且该bean仅在当前HTTP session内有效。
- Global Session:类似于标准的 HTTP Session 作用域,不过它仅仅在基于 portlet 的 web 应用中才有意义。Portlet 规范定义了全局 Session 的概念,它被所有构成某个 portlet web 应用的各种不同的 portlet 所共享。在 global session 作用域中定义的 bean 被限定于全局 portlet Session 的生命周期范围内。如果你在 web 中使用 global session 作用域来标识 bean,那么 web 会自动当成 session 类型来使用。
8.@Resource和@Autowired的区别?
- @Resource是按byName自动注入,它有两个属性,name和type。如果使用name属性,则从上下文中查找名字匹配的bean进行装配,找不到则抛出异常;如果指定了type,则从上下文中找到类型匹配的唯一bean进行装配,找不到或者找到多个,都会抛出异常;如果同时制定了name和type,则从Spring上下文中找到唯一匹配的bean进行装配,找不到则抛出异常;如果两个都没有指定,默认按照byName方式进行装配。
- @Autowired是按照type进行匹配。
9.循环依赖问题
9.1 Setter方法注入
/** Cache of singleton objects: bean name --> bean instance 缓存单例实例化对象 */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(64);
/** Cache of singleton factories: bean name --> ObjectFactory 缓存单例对象工厂 */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<String, ObjectFactory<?>>(16);
/** Cache of early singleton objects: bean name --> bean instance 缓存早期的单例对象*/
private final Map<String, Object> earlySingletonObjects = new HashMap<String, Object>(16);
- 一级缓存singletonObjects :单例实例化对象
- 二级缓存earlySingletonObjects:早期单例对象
- 三级缓存singletonFactories:单例对象工厂
/**
* @param beanName 要寻找的Bean的名称
* @param allowEarlyReference 是否应该创建早期引用
**/
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
//首先从一级缓存单例实例中查找
Object singletonObject = this.singletonObjects.get(beanName);
//如果一级缓存中没有并且对象正在被创建
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
//从二级缓存早期的单例对象中获取
singletonObject = this.earlySingletonObjects.get(beanName);
//如果二级缓存中没有并且允许创建早期引用
if (singletonObject == null && allowEarlyReference) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
//从三级缓存中移除相应的实例并放入二级缓存中
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return (singletonObject != NULL_OBJECT ? singletonObject : null);
}
protected void addSingletonFactory(String beanName, ObjectFactory singletonFactory) {
Assert.notNull(singletonFactory, "Singleton factory must not be null");
synchronized (this.singletonObjects) {
if (!this.singletonObjects.containsKey(beanName)) {
this.singletonFactories.put(beanName, singletonFactory);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
}
无法解决构造器循环依赖的问题。例如Spring容器先创建单例A,A依赖B,然后A放在“当次创建Bean池”中,此时创建B,B依赖C,然后B放在“当前创建Bean池”中,此时创建C,C又依赖A,但是,此时A已经在池中,所以会报错。
10.拦截器和过滤器
10.1 过滤器
依赖于servlet容器。实现上,基于函数回调,可以对几乎所有的请求进行过滤,但是一个过滤器实例只能在容器初始化时调用一次。常用于修改字符编码,修改HttpServletRequest的参数。
10.2 拦截器
依赖于Spring框架。实现上,基于Java反射机制,属于AOP的一种运用,就是在service或者一个方法前,调用一个方法,或者在方法后,调用一个方法。一个拦截器在一个controller生命周期之内可以多次调用。但是缺点是只能对controller请求进行拦截,对其他的一些比如直接访问静态资源的请求则没办法进行拦截处理。
11. SpringMVC流程
SpringMVC流程具体步骤:
- 首先用户发送请求——>DispatcherServlet,前端控制器收到请求后自己不进行处理,而是委托给其他的解析器进行处理,作为统一访问点,进行全局的流程控制;
- DispatcherServlet——>HandlerMapping,HandlerMapping 将会把请求映射为 HandlerExecutionChain 对象(包含一个 Handler 处理器(页面控制器)对象、多个 HandlerInterceptor 拦截器)对象,通过这种策略模式,很容易添加新的映射策略;
- DispatcherServlet——>HandlerAdapter,HandlerAdapter 将会把处理器包装为适配器,从而支持多种类型的处理器,即适配器设计模式的应用,从而很容易支持很多类型的处理器;
- HandlerAdapter——>处理器功能处理方法的调用,HandlerAdapter 将会根据适配的结果调用真正的处理器的功能处理方法,完成功能处理;并返回一个 ModelAndView 对象(包含模型数据、逻辑视图名);
- ModelAndView 的逻辑视图名——> ViewResolver, ViewResolver 将把逻辑视图名解析为具体的 View,通过这种策略模式,很容易更换其他视图技术;
- View——>渲染,View 会根据传进来的 Model 模型数据进行渲染,此处的 Model 实际是一个 Map 数据结构,因此很容易支持其他视图技术;
- 返回控制权给 DispatcherServlet,由 DispatcherServlet 返回响应给用户,到此一个流程结束。
用户首先发起请求到Dispatcher Servlet,servlet将请求发给HandlerMapping,HandlerMapping返回给servlet一个HandlerExecutionChain(包含一个Handler处理器、多个HandlerInterceptor拦截器),servlet再将Handler处理器发给HandlerAdapter,调用相应的处理方法返回ModelAndView。servlet再将ModelAndView通过ViewResolver解析为具体的View。最后根据Model模型数据进行渲染,将结果返回给用户。
12. SpringBoot 的优点?
- 内置容器
- 通过starter简化Maven配置
- 健康检测
13. servlet生命周期?
Servlet体系结构是建立在Java多线程机制上,生命周期由Web容器负责。当客户端第一次请求某个Servlet时,Servlet容器将会根据web.xml的配置文件实例化这个Servlet类。当有新的客户端请求该Servlet时,一般不会再实例化该Servlet类。当有多个请求时,Servlet容器会起多个线程来访问同一个Servlet实例的servic()方法。
- 调用init()方法初始化
- 调用service()方法来处理客户端请求
- 调用destory()方法来释放资源,标记自身可回收
- 被垃圾回收器回收
14.Spring的功能模块?
- SpringCore:主要实现IOC功能
- AOP
- ORM:对ORM框架的管理和支持(hibernate)
- DAO:提供JDBC支持
- WEB:对struts的支持等
- Context:提供Bean的访问方式
- MVC
网友评论