1. Spring优点:
a. 低侵入式设计,代码的污染极低。b.独立于各种应用服务器,基于Spring框架的应用,可以真正实现write once、run anywhere的承诺。c.Spring的IOC容器降低了业务对象替换的复杂性,提高了组件之间的解耦。d.Spring的AOP支持允许将一些通用任务和安全、事务、日志等进行集中式管理,从而提供了更好的服用。e.Spring的ORM(对象关系映射,虚拟对象数据库)和DAO(面向对象的数据库接口)提供了与第三方持久层框架的良好整合,并简化了底层的数据库访问。f.Spring的高度开放性,并不强制应用完全依赖于Spring,开发者可自由选用Spring框架的部分或全部。
2. Spring的核心机制
A. 管理Bean:程序主要是通过Spring容器来访问容器中的Bean,ApplicationContext是Spring容器最常用的接口,该接口有两个实现类:ClassPathXmlApplicationContext从类加载路径下搜索配置文件,并根据配置文件来创建Spring容器;FileSystemXmlApplicationContext从文件系统的相对路径下去搜索配置文件,并根据配置文件来创建Spring容器。
B.依赖注入:Spring框架的核心功能有两个:Spring容器作为超级大工厂,负责创建、管理所有的Java对象,这些Java对象被称为Bean。Spring容器管理容器中Bean之间的依赖关系,Spring使用一种被称为“依赖注入”的方式来管理Bean之间的依赖关系。使用依赖注入不仅可以为Bean注入普通的属性值,还可以注入其他的Bean的引用。依赖注入是一种优秀解耦方式,其可以让Bean以配置文件组织在一起而不是以硬编码的方式耦合在一起。
依赖注入是一个高度重视以配置文件来管理Java实例的,也叫控制反转。当某个Java对象需要调用另一个Java对象的方法时,在传统模式下通常有两种做法:原始做法:调用者主动创建被依赖对象,然后再调用被依赖对象的方法;简单工厂模式:调用者先找到被依赖对象的工厂,然后主动通过工厂去获取被依赖对象,最后再调用被依赖对象的方法。使用Spring之后,调用者无需主动获取被依赖对象,调用者只要被动接受Spring容器为调用者的成员变量赋值使用Spring后调用者获取对象的方式由原来的主动获取变成了被动接受所以称为控制反转。从Spring容器的角度来看,Spring容器负责将被依赖对象赋值给调用者的成员变量,相当于为调用者注入它所依赖的实例,因此被称为依赖注入。注入方式主要有设值注入和构造注入。
设值注入指IOC容器通过成员变量的setter的方法来注入被依赖对象。这种注入方式简单、直观,因此再Spring得依赖注入里大量使用。构造注入指利用构造器来设置依赖关系得方式,就是驱动Spring在底层以反射方式执行带指定参数得构造器,当执行带参数得构造器时,就可以利用构造器参数对成员变量执行初始化。
Spring中的Bean:对于开发者来说,开发者使用Spring框架主要做两件事:开发Bean,配置Bean。对于Spring框架来说,它要做得就是根据配置文件来创建Bean实例,并调用Bean实例得方法完成依赖注入。
创建Bean得3种方式:a.使用构造器创建Bean实例;b.使用静态工厂方法创建Bean;c.调用实例工厂方法创建Bean。
3. SpringMvc流程
a. 用户发送请求至前端控制器DispatcherServelt;
b. DispatcherServelt收到请求调用HandlerMapping处理器映射器;
c. 处理器映射器找到具体的处理器,生成处理器对象及处理器拦截器一并返回给DispatcherServelt;
d. DispatcherServelt调用HandlerAdapter处理器适配器;
e. HandlerAdapter经过适配器调用具体的处理器(如Controller,也叫后端处理器);
f. Controller执行完成返回ModelAndView;
g. HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServelt;
h. DispatcherServelt将ModelAndView传给ViewReslover视图解析器;
i. ViewReslover解析后返回具体View;
j. DispatcherServelt根据View进行渲染视图(即将模型数据填充至视图中);
k. DispatcherServelt响应用户。
4. SpringMVC中的元素
DispatcherServelt:DispatcherServelt是前端控制器设计模式的实现,提供Spring Web MVC的集中访问点,而且负责职责的分派,而且与Spring IOC容器无缝集成。主要职责为:a.文件上传解析;b.通过HandlerMapping(处理器映射器)将请求映射到处理器(返回一个HandlerExecutionChain,它包括一个处理器,多个HandlerInterceptor拦截器);c.通过HandlerAdapter(处理器适配器)支持多种类型的处理器(HandlerExecutionChain中的处理器);d.通过ViewReaolver解析逻辑视图名到具体视图实现;e.本地渲染视图;f.在执行过程中遇到异常交给HandlerExceptionResolver来解析。
5. AOP:
概念:aop是建立在Java反射基础上,具体是指散落在程序中公共部分提取出来,做成了切面类,这样做的好处在于代码的重用。一旦涉及到该功能的需求发生变化,只要修改该代码就行。Aop的实现主要由JDK的动态代理与CGLIB代码。
意义:增强类的功能(在目标对象的方法执行之间和执行之后);各个步骤之间的良好隔离性耦合性大大降低;源代码无关性,再拓展功能的同时不对源码进行修改操作。
原理:静态代理:AspectJ,AOP框架会在编译阶段将Aspect织入Java字节码中。
动态代理:AOP框架不会去修改字节码,而是在内存中临时为方法生成一个AOP对象,这个对象包含了目标对象的全部方法,并在特定的切点去做了增强处理,并回调原对象方法。主要有JDK动态代理(接口)和CGLIB动态代理(继承),JDK动态代理主要通过反射来接收被代理的类,并且要求被代理的类必须实现一个接口。
静态代理:由程序员创建或特定工具自动生成源代码,也就是在编译时就已经将接口,被代理类,代理类等确定下来。在程序运行之前,代理类的.class文件就已经生成。
动态代理,代理类并不是在Java代码中定义的,而是在运行时根据我们在Java代码中的“指示”动态生成的。
6. IOC
当某个角色需要另外一个角色协助的时候,在传统的程序设计过程中,通常由调用者来创建被调用者的实例对象。但在spring中创建被调用这的工作不再由调用者来完成,因此称为控制反转。创建被调用者的工作由spring来完成,然后注入调用者直接使用。
7. Spring常见创建对象的注解:
@Component@Controller@Service@Repository
8. Spring中用到的设计模式:
简单工厂、工厂方法(在各种BeanFactory以及ApplicationContext创建);
单例模式(在创建bean的时候)、适配器、
外观模式(在Tomcat中很多场景都用到了外观模式,因为Tomcat中有很多不同的组件,每个组件需要相互通信,但又不能将自己内部数据过多地暴露给其他组件)、
代理模式(Aop实现中用到了JDK的动态代理)、
观察者、
策略模式:Comparator这个接口,复合对象排序
原型模式:使用原型模式创建对象比直接new一个对象在性能上好得多,因为Object类的clone()方法是一个native方法,它直接操作内存中的二进制流,特别是复制大对象时性能的差别非常明显。
模板方法(在各种BeanFactory以及ApplicationContext实现)。
9. Spring的核心类有哪些,有什么作用?
BeanFactory:负责读取bean配置文档,管理bean的加载,实例化,维护bean之间的依赖关系,负责bean的声明周期。
BeanWrapper:提供统一的get和set方法,ioc容器来访问bean的属性。
ApplicationContext:提供框架的实现,包括BeanFactory的所有功能。
10. Spring中自动装配的方式有哪些?
a. No:即不启用自动配置;
b. byName:通过属性的名字的方式查找JavaBean依赖的对象并为其注入。比如说类有个属性printer,指定其autowire属性为byName后,Spring
IOC容器会在配置文件中查找id/name属性为printer的bean,然后使用Seter方法为其注入。
c. ByType:通过属性的类型查找JavaBena依赖的对象并为其注入。
d. Constructor:同byType一样,也是通过类型查找依赖对象,与byType的区别在于它不是使用Seter方法注入,而是使用构造子注入。
e. Autodetect:在byType和constructoe之间自动的选择注入方式。
f. Default:由上级标签<beans>的default-autowire属性确定。
11. Spring的事务管理:
Spring中的事务管理一般是使用TransactionManager进行管理,可以通过Spring的注入来完成此功能。
Spring几个关于事务处理的类:
TransactionDefinition//事务属性定义
TransactionStatus//代表了当前的事务,可以提交、回滚
PlatformTransactionManager这个是spring提供的用于管理事务的基础接口,其下有一个实现的抽象类AbstractPlatformTransactionManager,我们使用的事务管理类例如DataSourceTransactionManager等都是这个类的子类。
Spring提供的事务管理可以分为两类:编程式(transactionTemplate)的和声明式(TransactionProxyFactoryBean)的。编程式的比较灵活,但是代码量大,存在重复的代码比较多;声明式的比编程式的更灵活。
12. Bean的调用:
a. 使用BeanWrapper
b. 使用BeanFactory
c. 使用ApplicationContext
13. Bean的销毁
a. 使用配置文件中的destory-method属性
b. 实现org.springframwork.bean.factory.DisposeableBean接口
14. AOP里面重要的几个名词:
切面(Aspect):一个关注点的模块化,这个关注点可能会横切多个对象。在Spring AOP中,切面可以使用通用类或者在普通类中以@Aspect注解来实现。
连接点(Joinpoint):在程序执行过程中某个特定的点,比如某方法调用的时候或处理异常的时候。在Spring AOP中,一个连接点总是代表一个方法的执行。通过声明一个org.aspect.lang.JoinPoint类型的参数可以使通知的主体部分获得连接点信息。
通知(Advice):在切面的某个特定的连接点(Joinpoint)上执行的动作。通知有各种类型,其中包括“around”、“before”和“after”等通知。许多AOP框架包括Spring都是以拦截器做通知模型,并维护一个以连接点为中心的拦截器链。
切入点(Pointcut):匹配连接点的断言。通知和一个切入点表达式关联,并在满足这个切入点的连接点上运行。切入点表达式如何匹配是AOP的核心:Spring缺省使用AspectJ切入点语法。
引入(Introduction):声明额外的方法或者某个类型的字段。Spring允许引入新的接口到任何被代理的对象。
AOP代理(AOP Proxy):AOP框架创建的对象,用来实现切面契约(aspect contract)。在spring中,AOP代理可以是JDK动态代理或者CGLIB代理。
织入(Weaving):把切面(aspect)连接到其他的应用程序类型或者对象上,并创建一个被通知的对象。
15. Springmvc常用注解
@Controller:用于标记一个类,使用它标记的类就是一个SpringMVC
Controller对象。@Controller只是定义了一个控制器类,而使用@RequestMapping注解的方法才是真正处理请求的处理器。单单使用@Controller标记在一个类上还不能被Spring认识,需要Spring来管理。a.在SpringMVC的配置文件中定义MyController的Bean对象;b.在SpringMVC的配置文件中告诉Spring该到哪里去找标记为@Controller的Controller控制器。
@RequestMapping:是一个用来处理请求地址映射的注解,可用于类或方法上。
@Resource:做Bean的注入时使用,其实它不是Spring的注解,他的包是javax.annotation.Resource,需要导入,但是Spring支持该注解的注入。默认按照ByName自动注入,@Resource有两个重要属性:name和type,spring将@Resource注解的name属性解析为bean的名字,而type属性则解析为bean的类型。
@Autowired:做Bean的注入时使用。它是按照byType装配依赖对象,如果我们想使用byName来装配,可以结合@Qualifier注解一起使用。
@ModelAttribute和@SessionAttributes:该Controller的所有方法在调用前,先执行此@ModelAttribue方法,可用于注解和方法参数中,可以把@ModelAttribute特性,应用在BaseController当中,所有的Controller继承BaseController,即可实现在调用Controller时,先执行@ModelAttribute方法。@SessionAttributes即将值放到session作用域中,写在class上面。
@PathVariable:用于将请求URL中的模板变量映射到功能处理方法的参数上,即取出uri模板中的变量作为参数。
@requestParam:主要用于在SpringMVC后台控制层获取参数。
@ResponseBody:将注解用于将Controller的方法返回的对象,通过适当的HttpMessageConverter转换为指定格式后,写入到Response对象的body数据区。
16. Java过滤器:示例
a. 在传入的request、response提前过滤掉一些信息、提前设置一些参数、统一设置字符集、控制是否登录等,然后再传入Servelt等中进行处理。
b. Filter链:一个web应用中,可以编写多个Filter,这些Filter组合起来称为一个Filter链,web服务器根据Filter在web.xml文件中的注册顺序决定先调用哪个Filter。
17. SpringMVC拦截器
a. 拦截器是面向切面编程的,依赖的技术是java的动态代理(拦截器是被包裹在过滤器中的)。
b. 拦截器栈:就是将拦截器按一定的顺序联接成一条链,在访问被拦截的方法或字段时,拦截器链中的拦截器就会按其之前定义的顺序被调用。
18. Java监听器
a. Servelt的监听器listener,它是实现了javax.servelt.ServeltContextListener接口的服务器端程序,它也是随web应用的启动而启动,只初始化一次随web应用的停止而销毁。
b. 主要作用是:做一些初始化的内容添加工作、设置一些基本的内容.
19. SpringMVC过滤器和拦截器的区别:(原文地址)
a. 拦截器是基于java的反射机制的,而过滤器是基于函数回调。
b. 拦截器不依赖于servelt容器,过滤器依赖于servelt容器。
c. 拦截器只能对action请求起作用,而过滤器则可以对几乎所有请求起作用。
d. 拦截器可以访问action上下文、值栈里的对象,而过滤器不能访问。
e. 在action的声明周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次。
f. 拦截器可以获取IOC容器中的各个bean,而过滤器就不行,在拦截器里注入一个serivice可以调用业务逻辑。
20. @RequestMapping的参数和用法
RequestMapping是一个用来处理请求地址映射的注解,可用于类或方法上。
类定义处:提供初步的请求映射信息。相对于WEB应用的根目录。
方法处:提供进一步的细分映射信息。相对于类定义处的URL。
RequestMapping注解有6个属性。(网址)
(1). value和method;
value:指定请求的实际地址。
method:指定请求的method类型,GET, POST,PUT,DELETE等。(405)
(2). consumes和produces:
consumes:指定处理请求的提交内容类型,例如application/json,text/html。(415)
Produces:指定返回的内容类型,仅当request请求头中的(Accept)类型中包含指定类型才返回。
(3). params和headers:
params:指定request中必须包含某些数值时,才让该方法处理。(400)
header:指定request中必须包含某些指定的header值,才能让该方法处理请求。(404)
21.Spring Bean作用域:
① singleton
使用该属性定义Bean时,IOC容器仅创建一个Bean实例,IOC容器每次返回的是同一个Bean实例。
② prototype
使用该属性定义Bean时,IOC容器可以创建多个Bean实例,每次返回的都是一个新的实例。
③ request
该属性仅对HTTP请求产生作用,使用该属性定义Bean时,每次HTTP请求都会创建一个新的Bean,适用于WebApplicationContext环境。
④ session
该属性仅用于HTTP Session,同一个Session共享一个Bean实例。不同Session使用不同的实例。
⑤ global-session
该属性仅用于HTTP Session,同session作用域不同的是,所有的Session共享一个Bean实例。
22.Bean的生命周期:
Servlet的生命周期:实例化,初始init,接收请求service,销毁destroy;
(1)实例化一个Bean--也就是我们常说的new;
(2)按照Spring上下文对实例化的Bean进行配置--也就是IOC注入;
(3)如果这个Bean已经实现了BeanNameAware接口,会调用它实现的setBeanName(String)方法,此处传递的就是Spring配置文件中Bean的id值
(4)如果这个Bean已经实现了BeanFactoryAware接口,会调用它实现的setBeanFactory(setBeanFactory(BeanFactory)传递的是Spring工厂自身(可以用这个方式来获取其它Bean,只需在Spring配置文件中配置一个普通的Bean就可以);
(5)如果这个Bean已经实现了ApplicationContextAware接口,会调用setApplicationContext(ApplicationContext)方法,传入Spring上下文(同样这个方式也可以实现步骤4的内容,但比4更好,因为ApplicationContext是BeanFactory的子接口,有更多的实现方法);
(6)如果这个Bean关联了BeanPostProcessor接口,将会调用postProcessBeforeInitialization(Object obj, String s)方法,BeanPostProcessor经常被用作是Bean内容的更改,并且由于这个是在Bean初始化结束时调用那个的方法,也可以被应用于内存或缓存技术;
(7)如果Bean在Spring配置文件中配置了init-method属性会自动调用其配置的初始化方法。
(8)如果这个Bean关联了BeanPostProcessor接口,将会调用postProcessAfterInitialization(Object obj, String s)方法、;
注:以上工作完成以后就可以应用这个Bean了,那这个Bean是一个Singleton的,所以一般情况下我们调用同一个id的Bean会是在内容地址相同的实例,当然在Spring配置文件中也可以配置非Singleton,这里我们不做赘述。
(9)当Bean不再需要时,会经过清理阶段,如果Bean实现了DisposableBean这个接口,会调用那个其实现的destroy()方法;
(10)最后,如果这个Bean的Spring配置中配置了destroy-method属性,会自动调用其配置的销毁方法。
一旦把一个bean纳入到Spring IoC容器之中,这个bean的生命周期就会交由容器进行管理,一般担当管理者角色的是BeanFactory或ApplicationContext。
23.Spring处理循环依赖:
用递归的方法找出当前Bean的所有依赖Bean, 然后所有提前缓存起来。
setter循环依赖(对于setter注入造成的依赖是通过Spring容器提前暴露刚完毕构造器注入但未完毕其它步骤(如setter注入)的Bean来完毕的,并且仅仅能解决单例作用域的Bean循环依赖)详细处理过程例如以下:
(1) Spring容器创建单例“circularityA” Bean。首先依据无參构造器创建“circularityA” Bean, 并暴露一个exposedObject用于返回提前暴露的Bean。并将“circularityA”Bean放到Catch中。然后进行setter注入“circularityB”;
(2) Spring容器创建单例“circularityB" Bean。首先依据无參构造器创建“circularityB" Bean,并暴露一个exposedObject用于返回提前暴露的Bean。并将“circularityB” Bean放到Catch中,然后进行setter注入“circularityC”;
(3) Spring容器创建单例“circularityC” Bean,首先依据无參构造器创建“circularityC” Bean,并暴露一个exposedObject用于返回暴露的Bean。并将“circularityC” Bean放入Catch中, 然后进行setter注入“circularityA”。进行注入“circularityA”时因为步骤1提前暴露了exposedObject所以从之前的catch里面拿Bean不用反复创建。
(4) 最后在依赖注入“circularityB”和“circularityA”也是从catch里面拿提前暴露的bean。 完毕setter注入。
可是对于“prototype”作用域Bean。Spring容器无法完毕依赖注入,由于“prototype”作用域的Bean,Spring容器不进行缓存,因此无法提前暴露一个创建中的Bean。
另一种Spring无法解决的循环依赖方式----构造器循环依赖
如在创建CircularityA类时,构造器须要CircularityB类。那将去创建CircularityB,在创建CircularityB类时又发现须要CircularityC类,则又去创建CircularityC,终于在创建CircularityC时发现又须要CircularityA。 形成环状依赖, 从而被Spring抛出。
网友评论