spring IOC与AOP

spring是什么?

spring是一个轻量级的ioc和aop容器框架

常见的配置方式:基于XML配置,基于注解的配置,基于java的配置

 

spring的优点?

1)spring属于低侵入式设计,对代码的污染极低

2)spring的DI机制将对象之间的依赖关系交由框架处理,降低组件的耦合性

3)spring提供了AOP技术,支持将一些通用任务集中管理,从而得到更好的复用

4)spring对主流的应用框架提供了集成支持

 

 

 

对spring AOP的理解?

AOP一般称为面向切面,是面向对象的一种补充,用于将那些与业务无关,但却对多个对象产生影响的公共行为和逻辑,抽取并封装为一个可重用的模块。能够减少系统中的重复代码,降低模块间的耦合度,同时提高了系统的可维护性

AOP实现的关键在于代理模式,AOP代理主要分为静态代理和动态代理。 静态代理的代表为:AspectJ       动态代理则以Spring Aop为代表

1)AspectJ是静态代理的增强(静态代理是Aop框架会在编译阶段生成AOP代理类,因此也成为编译时增强),他会在编译阶段将切面织入java字节码中,运行的时候就是增强之后的AOP对象

2)Spring AOP使用的动态代理(动态代理就是说AOP框架不会去修改字节码,而是每次运行时在内存中临时为方法生成一个AOP对象,这个AOP对象包含了目标对象的全部方法,并且在特定的切点做了增强处理,并回调原对象的方法)

Spring AOP中的动态代理分为jdk动态代理和CGLIB动态代理

jdk动态代理:只提供接口的代理,不支持类的代理,核心是InvocationHandler接口和Proxy类,InvocationHandler通过invoke()方法反射来调用目标类中的代码,动态地将横切逻辑和业务编制在一起,接着,Proxy利用InvocationHandler动态创建一个符合某一接口的示例,生成目标类的代理对象

CGLIB动态代理:如果代理类没有实现InvocationHandler接口,那么Spring AOP会选择CGLIB来动态代理目标类。CGLIB是一个代码生成的类库,可以在运行时动态的生成类的一个子类对象,并且覆盖其中特定方法并添加增强代码,从而实现AOP,CGLIB通过继承的方式做动态代理,如果某个类被标记为final,那么无法使用CGLIB做动态代理

 

静态代理和动态代理的区别:生成Aop代理对象的时机不同,相对来说AspectJ的静态代理方式性能更好,但是AspectJ需要特定的编译器进行处理,而Spring Aop不需要特定的编译器

 

哪些类不能被动态代理?

  1.final类

  2.只有有参构造器的类,因为通过继承方式的动态代理必须要显示地指定无参构造器

 

 

 

 

Spring IOc的理解?

1.  IOC就是控制反转,是指创建对象的控制权的转移,以前创建对象的主动权和时机是由自己把控的,而现在把这种权利转移到Spring容器中,并由容器根据配置文件去创建实例和管理各个实例之间的依赖关系,对象与对象之间松散耦合,有利于复用。DI依赖注入和控制反转是同一个概念的不同角度的描述

2. 最直观的表达就是,IOC让对象的创建不用去new,可以由spring自动产生,使用java的反射机制,根据配置文件在运行时动态的去创建对象以及管理对象,并调用对象的方法的

3. Spring IOC的三种注入方式:构造器注入,setter注入,注解注入

4.IOC负责创建对象,管理对象,装配对象,配置对象,并且管理对象的整个生命周期

作用:管理对象的创建和依赖关系的维护,由容器去维护具体对象,实现解耦,托管了类是产生过程

好处:ioc把应用的代码量降到最低,使程序易于测试,用最小的代价和最小的侵入性使松散耦合得意实现,支持加载服务时的饿汉式初始化和懒加载

工作过程:

1:初始化ioc容器

2:读取配置文件

3:将配置文件转换为容器识别的数据结构

4:利用数据结构一次实例化相应的对象

5:注入对象的依赖关系

 

spring加载bean的过程?

   1.获取配置文件资源:通过ResourceLoader来完成资源文件位置的定位

    2.对bean定义信息进行解析:通过BeanDefinitionReader来完成bean定义信息的解析

    3.加载提取bean并注册:ioc容器解析得到BeanDefinition后,会把它在ioc容器中注册

   4.通过DefaultListableBeanFactory方法来完成初始化

 

实现机制:工厂模式+反射+xml文件

 

 

BeanFactory和ApplicationContext有什么区别?

        BeanFactory和ApplicationContext是Spring的两大核心接口,都可以当做Spring的容器。其中ApplicationContext是BeanFactory的子接口。

(1)BeanFactory:是Spring里面最底层的接口,包含了各种Bean的定义,读取bean配置文档,管理bean的加载、实例化,控制bean的生命周期,维护bean之间的依赖关系。ApplicationContext接口作为BeanFactory的派生,除了提供BeanFactory所具有的功能外,还提供了更完整的框架功能:

①继承MessageSource,因此支持国际化。

②统一的资源文件访问方式。

③提供在监听器中注册bean的事件。

④同时加载多个配置文件。

⑤载入多个(有继承关系)上下文 ,使得每一个上下文都专注于一个特定的层次,比如应用的web层。

(2)①BeanFactroy采用的是延迟加载形式来注入Bean的,即只有在使用到某个Bean时(调用getBean()),才对该Bean进行加载实例化。这样,我们就不能发现一些存在的Spring的配置问题。如果Bean的某一个属性没有注入,BeanFacotry加载后,直至第一次使用调用getBean方法才会抛出异常。

        ②ApplicationContext,它是在容器启动时,一次性创建了所有的Bean。这样,在容器启动时,我们就可以发现Spring中存在的配置错误,这样有利于检查所依赖属性是否注入。 ApplicationContext启动后预载入所有的单实例Bean,通过预载入单实例bean ,确保当你需要的时候,你就不用等待,因为它们已经创建好了。

        ③相对于基本的BeanFactory,ApplicationContext 唯一的不足是占用内存空间。当应用程序配置Bean较多时,程序启动较慢。

(3)BeanFactory通常以编程的方式被创建,ApplicationContext还能以声明的方式创建,如使用ContextLoader。

(4)BeanFactory和ApplicationContext都支持BeanPostProcessor、BeanFactoryPostProcessor的使用,但两者之间的区别是:BeanFactory需要手动注册,而ApplicationContext则是自动注册。
 

 

 

请解释Spring Bean的生命周期?

 首先说一下Servlet的生命周期:实例化,初始init,接收请求service,销毁destroy;

 Spring上下文中的Bean生命周期也类似,如下:

(1)实例化Bean:

对于BeanFactory容器,当客户向容器请求一个尚未初始化的bean时,或初始化bean的时候需要注入另一个尚未初始化的依赖时,容器就会调用createBean进行实例化。对于ApplicationContext容器,当容器启动结束后,通过获取BeanDefinition对象中的信息,实例化所有的bean。

(2)设置对象属性(依赖注入):

实例化后的对象被封装在BeanWrapper对象中,紧接着,Spring根据BeanDefinition中的信息 以及 通过BeanWrapper提供的设置属性的接口完成依赖注入。

(3)处理Aware接口:

接着,Spring会检测该对象是否实现了xxxAware接口,并将相关的xxxAware实例注入给Bean:

①如果这个Bean已经实现了BeanNameAware接口,会调用它实现的setBeanName(String beanId)方法,此处传递的就是Spring配置文件中Bean的id值;

②如果这个Bean已经实现了BeanFactoryAware接口,会调用它实现的setBeanFactory()方法,传递的是Spring工厂自身。

③如果这个Bean已经实现了ApplicationContextAware接口,会调用setApplicationContext(ApplicationContext)方法,传入Spring上下文;

(4)BeanPostProcessor:

如果想对Bean进行一些自定义的处理,那么可以让Bean实现了BeanPostProcessor接口,那将会调用postProcessBeforeInitialization(Object obj, String s)方法。

(5)InitializingBean 与 init-method:

如果Bean在Spring配置文件中配置了 init-method 属性,则会自动调用其配置的初始化方法。

(6)如果这个Bean实现了BeanPostProcessor接口,将会调用postProcessAfterInitialization(Object obj, String s)方法;由于这个方法是在Bean初始化结束时调用的,所以可以被应用于内存或缓存技术;

    以上几个步骤完成后,Bean就已经被正确创建了,之后就可以使用这个Bean了。

(7)DisposableBean:

当Bean不再需要时,会经过清理阶段,如果Bean实现了DisposableBean这个接口,会调用其实现的destroy()方法;

(8)destroy-method:

最后,如果这个Bean的Spring配置中配置了destroy-method属性,会自动调用其配置的销毁方法。

 

 

 解释Spring支持的几种bean的作用域。

Spring容器中的bean可以分为5个范围:

(1)singleton:默认,每个容器中只有一个bean的实例,单例的模式由BeanFactory自身来维护。

(2)prototype:为每一个bean请求提供一个实例。

(3)request:为每一个网络请求创建一个实例,在请求完成以后,bean会失效并被垃圾回收器回收。

(4)session:与request范围类似,确保每个session中有一个bean的实例,在session过期后,bean会随之失效。

(5)global-session:全局作用域,global-session和Portlet应用相关。当你的应用部署在Portlet容器中工作时,它包含很多portlet。如果你想要声明让所有的portlet共用全局的存储变量的话,那么这全局变量需要存储在global-session中。全局作用域与Servlet中的session作用域效果相同。
 

 

 

Spring框架中的单例Beans是线程安全的么?

        Spring框架并没有对单例bean进行任何多线程的封装处理。关于单例bean的线程安全和并发问题需要开发者自行去搞定。但实际上,大部分的Spring bean并没有可变的状态(比如Serview类和DAO类),所以在某种程度上说Spring的单例bean是线程安全的。如果你的bean有多种状态的话(比如 View Model 对象),就需要自行保证线程安全。最浅显的解决办法就是将多态bean的作用域由“singleton”变更为“prototype”。
 

 

 

Spring如何处理线程并发问题?

在一般情况下,只有无状态的Bean才可以在多线程环境下共享,在Spring中,绝大部分Bean都可以声明为singleton作用域,因为Spring对一些Bean中非线程安全状态采用ThreadLocal进行处理,解决线程安全问题。

ThreadLocal和线程同步机制都是为了解决多线程中相同变量的访问冲突问题。同步机制采用了“时间换空间”的方式,仅提供一份变量,不同的线程在访问前需要获取锁,没获得锁的线程则需要排队。而ThreadLocal采用了“空间换时间”的方式。

ThreadLocal会为每一个线程提供一个独立的变量副本,从而隔离了多个线程对数据的访问冲突。因为每一个线程都拥有自己的变量副本,从而也就没有必要对该变量进行同步了。ThreadLocal提供了线程安全的共享对象,在编写多线程代码时,可以把不安全的变量封装进ThreadLocal。
 

 

 

Spring Bean的三种注入方式?

   1.基于xml注入:提供了setter注入和构造器注入。其中setter注入要求bean必须提供无参构造方法,还有提供注入对应属性的setter方法。而构造器注入需要使用元素的子元素来定义构造方法的参数

   2.基于java配置类的注入:该方式解决了xml配置的臃肿问题,通过@Configuration和@Bean注解

   3.基于注解的注入

 

 

 

 

Spring的自动装配:

在spring中,对象无需自己查找或创建与其关联的其他对象,由容器负责把需要相互协作的对象引用赋予各个对象,使用autowire来配置自动装载模式。

在Spring框架xml配置中共有5种自动装配:

(1)no:默认的方式是不进行自动装配的,通过手工设置ref属性来进行装配bean。

(2)byName:通过bean的名称进行自动装配,如果一个bean的 property 与另一bean 的name 相同,就进行自动装配。

(3)byType:通过参数的数据类型进行自动装配。

(4)constructor:利用构造函数进行装配,并且构造函数的参数通过byType进行装配。

(5)autodetect:自动探测,如果有构造方法,通过 construct的方式自动装配,否则使用 byType的方式自动装配。

基于注解的方式:

使用@Autowired注解来自动装配指定的bean。在使用@Autowired注解之前需要在Spring配置文件进行配置,<context:annotation-config />。在启动spring IoC时,容器自动装载了一个AutowiredAnnotationBeanPostProcessor后置处理器,当容器扫描到@Autowied、@Resource或@Inject时,就会在IoC容器自动查找需要的bean,并装配给该对象的属性。在使用@Autowired时,首先在容器中查询对应类型的bean:

如果查询结果刚好为一个,就将该bean装配给@Autowired指定的数据;

如果查询的结果不止一个,那么@Autowired会根据名称来查找;

如果上述查找的结果为空,那么会抛出异常。解决方法时,使用required=false
 

 

 

Spring 框架中都用到了哪些设计模式?

(1)工厂模式:BeanFactory就是简单工厂模式的体现,用来创建对象的实例;

(2)单例模式:Bean默认为单例模式。

(3)代理模式:Spring的AOP功能用到了JDK的动态代理和CGLIB字节码生成技术;

(4)模板方法:用来解决代码重复的问题。比如. RestTemplate, JmsTemplate, JpaTemplate。

(5)观察者模式:定义对象键一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知被制动更新,如Spring中listener的实现--ApplicationListener。
 

 

 

Spring事务的实现方式和实现原理:

Spring事务的本质其实就是数据库对事务的支持,没有数据库的事务支持,spring是无法提供事务功能的。真正的数据库层的事务提交和回滚是通过binlog或者redo log实现的。

(1)Spring事务的种类:

spring支持编程式事务管理和声明式事务管理两种方式:

①编程式事务管理使用TransactionTemplate。

②声明式事务管理建立在AOP之上的。其本质是通过AOP功能,对方法前后进行拦截,将事务处理的功能编织到拦截的方法中,也就是在目标方法开始之前加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务

 

@Transactional?

    基于spring AOP的事务管理即声明式事务管理,默认针对RuntimeException回滚主要有三种回滚方式:

                1.利用硬编码的方式,借助spring api对事务进行显示的回滚

                2.在spring配置文件中对rollback-for属性赋值

                3.针对业务代码进行封装,二次抛出RuntimeException类型的异常

 

 

@Component,@Controller,@Repository,@Service的区别?

  @Component:将java类标记为bean,它是任何spring管理组件的通用构件型

  @Controller:标记一个类成为控制器

  @Service:是组件注解的特化,可以在服务层使用@Service

  @Repository:它为DAO提供了额外的好处,将DAO倒入ioc容器

 

@Autowired有什么作用?

   可以更准确地控制应该在何处以及如何进行自动装配

 

@RequestMapping注解?

   用于将特定的http请求方法映射到将处理相应请求的控制器中的特定类/方法

 

 

SPringMVC的工作流程?

1.想服务器发送http请求,请求被控制器DispatcherServlet捕获

2.DispatchServlet根据server.xml中的配置对请求的url进行解析,等到uri,跟后根据uri调用handleMapping获得该handler配置的所有相关的对象

3.dispatchServlet根据获得的handler选择合适的handlerAdapter

4.提取request中的模型数据,填充handler,开始执行handler

5.处理请求后返回ModelAndView对象,dispatchServlet通过ViewResolver将逻辑视图转换为真正的视图

6.dispatchServlet通过model解析出ModelAndView()中的参数进行解析最终展现出完整的view给客户端

 

 

注解的原理?

   它本质上是继承了一个Annotation接口,具体实现类是java运行时生成的动态代理类。我们通过反射获取注解时,返回的是java

运行时生成的动态代理对象。通过代理对象调用自定义注解的方法,会最终调用annotationInvocationHandler的invoke方法得到对应的值

 

ioc的好处?

   对象的构建假如果依赖非常多的对象,并且层次很深的话,外层在构造对象时会很麻烦,而ioc帮我们管理对象的创建,只需要在配置文件里指定如何构建就行,最外层的对象不需要关心深层次对象是如何创建的。也就是假如我们修改深层次的对象的话,那么上层的所有类几乎都要去进行修改,这样的维护成本太高,而假如用ioc,我们只需要修改你要修改的那个类就行了,不用去修改其他上层楼,并且我们在创建实例时不需要了解他的细节。

 

 

为什么要有jdk动态代理和CGLIB动态代理?

    jdk动态代理(默认代理):由于子类要继承Proxy类,而java是单继承的,所以不能再继承了,这个时候就使用了接口,那么为什么要继承proxy类呢?因为proxy内部维护了一个invocationHandler对象进行invoke aop操作

   CGLIB动态代理:它是通过直接修改字节码进行增强子类,所以被代理的类不能是final的,那么为什么不继承Proxy呢?目的是调用父类的构造函数并使用子类传递给父类的invocationHandler来调用invoke

   总结:jdk代理只能基于接口代理(因为他已经继承了Proxy),CGLIB无论有没有实现接口都可以代理,因为它是通过继承的方式进行代理的,并没有去继承Proxy类,但是却无法继承final类
 

 

spring的事务传播机制?

    1.propagation_required:假如当前正要执行的事务不在另外一个事务里,那么就另起一个新的事务

    2.propagation_supports:如果当前在事务中,就以事务形式运行,不在一个事务中,就以非事务的形式运行

   3.propagation_mandatory:必须在一个事务中运行,只能被一个父事务调用,否则抛出异常

   4.propagation_requires_new:新建事务完成以后,上下文事务在恢复运行

  5.propagation_not_supported:当前不支持事务

  6.propagation_never;不能再事务中运行

  7.propagation_nested:该事务和它的父事务是相互依赖的,要和父事务一起提交,一起回滚

 

 

Servlet的生命周期,执行过程?

   生命周期:加载对应的Servlet类,实例化Servlet(构造函数运行),调用init方法,调用service方法,执行destroy方法

  执行过程:浏览器向服务器发出一个url请求,根据url找到对应的servlet执行init方法,然后创建servletRequest对象和servletResponse对象,调用service方法,执行goGet或者doPost,也就是自己重写的方法,最后得到结果响应给浏览器

 

servlet,filter,listener,interceptor的区别?

   servlet:创建并返回一个包含基于客户请求性质的动态内容的完整html页面

   filter:能够在一个请求到达servlet之前预处理用户请求,也可以在离开servlet时处理http响应

  listener:主要就是用于监听servletContext,httpsession,servletRequest的

  interceptor:与过滤器相似,处理用户的请求和响应

 

springboot与spring?

  springboot是spring框架的扩展,它消除了设置spring应用程序所需的复杂例行配置

 特征(区别):1.通过提供的starters简化构建配置

            2.嵌入式的tomcat

            3.尽可能的自动配置spring

           4.可以直接通过main函数启动,嵌入式web服务器,避免了应用程序部署的复杂性

           5.无需再像spring那样有一堆xml文件配置

           6.提供了pom可以简化maven的配置

 

springboot中的@Bean?

   @Bean标注在方法上(返回某个实例的方法),等价于spring的xml配置文件中的<bean>,作用就是注册bean对象

      1)@Bean注解在返回实例的方法上,如果未通过@bean指定的名称,则默认与标注的方法名相同

      2)@Bean注解默认作用域为singleton作用域,可以通过@Scope来设置其他作用域

 

使用xml注册bean和使用注解@Bean注册对象之间有什么明显的区别?

    加载对象存在一定的先后顺序时会出现循环加载bean的问题(@Bean)

     

spring启动执行流程?

  1.web.xml中提供了ContextLoaderListener

  2.web容器启动时会进行初始化执行ContextLoaderListener中的contextInitialized方法

  3.调用父类的initWebApplicationContext方法(在initWebApplicationContextinitlized中会执行三个任务:

                                                                          1.创建WebApplicationContext容器

                                                                           2.加载spring配置文件

                                                                          3.初始化配置文件以及配置文件里面的bean)

  4.结束调用ContextLoaderListener里面的ContextDistroyed方法,销毁Context容器

 

springmvc中的controller的返回值有哪些?

   1.ModelAndView

    2.String 

    3.void

    4.自定义返回类型

 

Servlet和Jsp的区别?

  1.jsp的本质就是Servlet,jvm只能识别java类,不能识别jsp的代码,web容器会将jsp的代码编译成jvm能够识别的java类

      jsp的工作原理:jsp页面在执行的时候会被服务端的jsp引擎转换为Servlet,然后又由jsp引擎调用java编译器,将servlet编译成class文件,并有jvm解释执行

   2.servlet的应用逻辑是在java文件中,从java代码中动态输出html,并且完全从表示层的html里分离开来,而jsp则是java和html组合成一个扩展名为.jsp的文件。jsp侧重于视图,servlet侧重于控制逻辑

 

Servlet中的filter?

   在Servlet中,我们有时候需要filter来进行对信息的过滤

    优点:1.过滤器是可插拔的,不需要某个过滤器时,直接删掉不会影响程序的运行

                2.一个过滤器不依赖于另一个资源

                3.维护少,容易维护

  过滤器的创建:实现Filter接口,该接口有如下方法

                           

 

然后Filter需要进行配置,比如在web.xml里配置filter和filter-mapping

 

循环引用的解决方法?

   1.使用@Autowired注解,由spring来决定对象属性的注入时机

   2.基于setter方法注入属性

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值