spring

作者: 蜡笔没了小新_e8c0 | 来源:发表于2019-04-17 09:11 被阅读0次

    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将请求发给HandlerMappingHandlerMapping返回给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

    相关文章

      网友评论

          本文标题:spring

          本文链接:https://www.haomeiwen.com/subject/xvmbwqtx.html