Spring概念

JavaBean是公共Java类,但是为了编辑工具识别,需要满足至少三个条件:

  1. 有一个public默认构造器(无参构造器)
  2. 属性使用public的get,set方法访问,也就是说属性设置成private,同时get,set方法与属性名的大小也需要对应。例如属性name,get方法就要写成,public String getName(){},N大写
  3. 能支持“事件”,例如addXXXXListener(XXXEvent e),事件可以是Click事件,Keyboard事件等等,也支持自定义的事件
  4. 提供反射机制, 这样能在运行时查看java bean 的各种信息
  5. 需要序列化。这个是框架,工具跨平台反映状态必须的

EJB(Enterprise Java Bean)在企业开发中,需要可伸缩的性能和事务、安全、分布式机制,这样能保证企业系统平滑发展,而不是发展到一种规模重新更换一套软件系统。然后有提高了协议要求,就出现了Enterprise Bean。EJB在Javabean基础上又提了一些要求:

  • JDBC:Java数据库连接
  • JNDI:Java命名和目录接口,通过一个名称就可以定位到一个数据源,连jdbc连接都不用了
  • RMI:远程过程调用,让一个机器上的java对象可以调用另外一个机器上的java对象,适应分布式要求
  • JMS:Java消息服务
  • JTA:Java事务管理,支持分布式事务,能在访问、更新多个数据库的时候,仍然保证事务还是分布式
  • Java mail : 收发邮件

POJO(Plain Old Java Object)有个叫Josh MacKenzie人觉得,EJB太复杂了,完全没必要每次都用,所以发明了个POJO。提供了一个Spring的容器来管理这些POJO,POJO其实是比javabean更纯净的简单类或接口。POJO的格式是用于数据的临时传递,它只能装载数据, 作为数据存储的载体,而不具有业务逻辑处理的能力。而JavaBean虽然数据的获取与POJO一样,但是JavaBean当中可以有其它的方法。

  1. 如果Bean依赖别的Bean,只需要声明即可,Spring容器负责把依赖的bean 给“注入进去”,起初大家称之为控制反转(IoC),后来改名:“依赖注入(DI)”。
  2. 如果Bean需要一些像事务、日志、安全这样的通用的服务,也只需要声明即可,Spring 容器在运行时能够动态的“织入”这些服务,这叫AOP。

DAO(data access objects)是数据访问对象,DAO一般有接口和该接口的实现类,接口用于规范实现类。实现类一般用于操作数据库,如对数据库进行修改、添加、删除等操作,一般直接调用公共类DAO。

我们通过DAO将POJO持久化为PO(Persistent Object),用PO组装出来VO(Value Object)DTO(Data Transfer Object)。比如:我们一张表有100个字段,那么对应的PO就有100个属性。但是我们界面上只要显示10个字段,客户端用WEBservice来获取数据,没有必要把整个PO对象传递到客户端,这时我们就可以用只有这10个属性的DTO来传递结果到客户端,这样也不会暴露服务端表结构.到达客户端以后,如果用这个对象来对应界面显示,那此时它的身份就转为VO。

BO(business object): POJO在业务层的体现,对于业务操作来说,更多的是从业务上来包装对象,如一个User的BO,可能包括name, age, sex, privilege, group等,这些属性在数据库中可能会在多张表中,因为每一张表对应一个PO,而我们的BO需要这些PO组合起来(或说重新拼装)才能成为业务上的一个完整对象。

MVC框架Struts2和SpringMVC的区别

  1. Struts2是类级别的拦截, 一个类对应一个request上下文,SpringMVC是方法级别的拦截,一个方法对应一个request上下文,因此容易实现restful API
  2. Struts2是多例的,每次请求都创建一个Action,类属性被方法共享,而SpringMVC是单例的,只有一个实例,方法之间变量不共享
  3. Struts2的核心控制器是Filter,SpringMVC的核心控制器是Servlet
  4. 拦截器方面,Struts2有自己的interceptor机制,SpringMVC用的是独立的AOP方式
  5. SpringMVC是Spring的一个模块,项目管理和安全性比Struts2好,配置文件少,并且集成了Ajax,处理ajax请求,直接通过返回数据,方法中使用注解@ResponseBody,能自动将对象转换为JSON数据。

ORM框架Hibernate和MyBaitis的区别

  1. MyBatis的sql语句是手动编写的,可以进行更为细致的SQL优化,可以减少查询字段,具有高度灵活,可优化,易维护的特点。但需要维护SQL和结果映射,工作量大
  2. Hibernate面向对象查询,以对象化的思维操作数据库,hql与具体的数据库无关,移植性更好。Hibernate无需编写SQL,映射的规则也可以由IDE生成,提高了开发效率,还提供了缓存、日志、级联等强大功能。但是对于多表关联复杂SQL、数据系统权限限制、根据条件编写SQL、存储过程等十分不便,性能难以通过SQL优化

加载顺序

当请求资源匹配多个 filter-mapping 时,filter 拦截资源是按照 filter-mapping 配置节出现的顺序来依次调用 doFilter() 方法的。servlet同filter类似。因此,完整的加载顺序是:context-param -> listener -> filter -> servlet,而同个类型之间的实际程序调用的时候的顺序是根据对应的mapping的顺序进行调用的。

Spring控制反转(IoC)

  • 软件系统在没有引入IoC容器之前,对象A依赖对象B,那么A对象在实例化或者运行到某一点的时候,自己必须主动创建对象B或者使用已经创建好的对象B,其中不管是创建还是使用已创建的对象B,控制权都在我们自己手上。
  • 如果软件系统引入了Ioc容器之后,对象A和对象B之间失去了直接联系,所以,当对象A实例化和运行时,如果需要对象B的话,IoC容器会主动创建一个对象B注入到对象A所需要的地方。

通过前面的对比,可以看到对象A获得依赖对象B的过程,由主动行为变成了被动行为,即把创建对象交给了IoC容器处理,控制权颠倒过来了,这就是控制反转的由来。

web.xml定义上下文

web.xml中存在两个contextConfigLocation,都是用于加载上下文。其中ContextLoadrListener是针对Spring的,会先加载;DispatcherServlet是针对SpringMVC的,后加载。区别:

  • ContextLoaderListener一般会加载整个Spring容器相关的bean配置管理(如: Log, Service, Dao, PropertiesLoader, etc.)
  • DispatcherServlet一般会加载MVC相关的bean配置管理(如: ViewResolver, Controller, MultipartResolver, ExceptionHandler, etc.)

注意:

  • 如果把@Controller的注解放到ContextLoadrListener中的配置文件去加载是不可以的,DispatcherServlet到时对这个Controller会无感知
  • DispatcherServlet的上下文仅仅是Spring MVC的上下文,而ContextLoaderListener的上下文则对整个Spring都有效。也就是DispatcherServlet可以使用Spring的上下文,但是Spring不能使用DispatcherServlet的上下文。一般Spring web项目中同时会使用这两种上下文

web.xml加载流程

  1. 启动web项目时,容器(tomcat或jetty)会读web.xml中两个节点
  2. 创建一个ServletContext上下文,WEB项目所有部分都将共享这个上下文
  3. 容器将转化为键值对,并交给ServletContext
  4. 容器创建中的类实例,即创建监听
  5. 在监听中会有contextInitialized(ServletContextEvent args)初始化方法,在这个方法中获得ServletContext = ServletContextEvent.getServletContext();
  6. web-app范围内的参数,可以通过getServletContext().getInitParameter(“context/param”)得到 servlet范围内的参数,只能在servlet的init()方法中取得,this.getInitParameter(“param1”)
  7. spring为我们提供了实现ServletContextListener接口的上下文初始化监听器:org.springframework.web.context.ContextLoaderListener。该监听器,默认读取/WEB-INF/下的applicationContext.xml文件。但是通过context-param指定配置文件路径后,便会去你指定的路径下读取对应的配置文件,并进行初始化

  8. 容器调用web.xml中配置的contextLoaderListener,初始化WebApplicationContext上下文环境(即IOC容器),加载context-param指定的配置文件信息到IOC容器中。WebApplicationContext在ServletContext中以键值对的形式保存。当容器初始化web.xml中配置的servlet,为其初始化自己的上下文信息servletContext,并加载其设置的配置信息到该上下文中。将WebApplicationContext设置为它的父容器
  9. 对于作用范围而言,在DispatcherServlet中可以引用由ContextLoaderListener所创建的ApplicationContext中的内容,而反过来不行。当Spring在执行ApplicationContext的getBean时,如果在自己context中找不到对应的bean,则会在父ApplicationContext中去找。这也解释了为什么我们可以在DispatcherServlet中获取到由ContextLoaderListener对应的ApplicationContext中的bean
  10. 那么web容器初始化webApplicationContext时作为公共的上下文环境,只需要将service、dao等的配置信息在这里加载,而servlet自己的上下文环境信息不需要加载。因此,在applicationContext.xml中将@Controller注释的组件排除在外,而在dispatcherServlet加载的配置文件中将@Controller注释的组件加载进来,方便dispatcherServlet进行控制和查找

Spring MVC

拦截器,过滤器,监听器,控制器,消息转换器,AOP执行顺序 过滤器(doFilter)->拦截器(preHandle)->消息转换器(readInternal)->AOP(@Before)->controller产生reponse->AOP(@After)->消息转换器(writeInternal)->拦截器(postHandle)

  1. 当web程序启动的时候,ContextLoaderServlet会把对应的配置文件信息读取出来,通过注射去初始化控制器DispatchServlet
  2. 当接受到一个HTTP请求的时候, DispatchServlet会让HandlerMapping去处理这个请求。HandlerMapping根据请求URL(不一定非要是URL,完全可以自定义,非常灵活)来选择一个Controller
  3. 然后DispatchServlet会在调用选定的Controller的handlerRequest方法,并且在这个方法前后调用这个Controller的interceptor(假如有配置的话),返回一个视图和模型的集合ModelAndView
  4. 框架通过ViewResolver来解析视图并且返回一个View对象,最后调用View的render方法返回到客户端

SpringMVC寻找最佳HttpMessageConverter过程:

  1. 首先获取注册的所有HttpMessageConverter集合
  2. 然后客户端的请求header中寻找客户端可接收的类型,比如Accept application/json,application/xml等,组成一个集合
  3. 所有的HttpMessageConverter都有canRead和canWrite方法,返回值都是boolean,看这个HttpMessageConverter是否支持当前请求的读与写,读对应@RequestBody注解, 写对应@ResponseBody注解
  4. 遍历HttpMessageConverter集合与前面获取可接受类型进行匹配,如果匹配直接使用当前第一个匹配的 HttpMessageConverter,然后return(一般是通过Accept和返回值对象的类型进行匹配)

常用注解:

  • @Service和@Repository放到实现类上面而不是接口类上面
  • @Component (把普通pojo实例化到spring容器中,相当于配置文件中的 ) 泛指各种组件,就是说当我们的类不属于各种归类的时候(不属于@Controller、@Services等的时候),我们就可以使用@Component来标注这个类
  • @Autowired:实际的注入装配动作是由BeanPostProcessor执行的,并且默认情况下使用AutowiredAnnotationBeanPostProcessor实现类完成。 区分一下@Autowired和@Resource两个注解的区别: 1、@Autowired默认按照byType方式进行bean匹配,@Resource默认按照byName方式进行bean匹配 2、@Autowired是Spring的注解,@Resource是J2EE的注解, https://blog.csdn.net/u013147600/article/details/49246169
  • @RequestMapping 是一个用来处理请求地址映射的注解,可用于类或方法上。用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径;用于方法上,表示在类的父路径下追加方法上注解中的地址将会访问到该方法,此处需注意@RequestMapping用在类上可以没有,但是用在方法上必须有。
  • @PathVariable 注解,其用来获取请求路径(url )中的动态参数
  • @RequestBody 前端代码必须采用POST请求(GET请求的输入是空)
  • @Responsebody 注解表示该方法的返回的结果直接写入 HTTP 响应正文(ResponseBody)中,一般在异步获取数据时使用,通常是在使用@RequestMapping后,返回值通常解析为跳转路径,加上@Responsebody后返回结果不会被解析为跳转路径,而是直接写入HTTP响应正文中
  • @RestController注解相当于@ResponseBody + @Controller合在一起的作用

fastjson SimplePropertyPreFilter filter = new SimplePropertyPreFilter(); filter.getIncludes().add(“status”); filter.getIncludes().add(“msg”); ObjectWithFilter owf = new ObjectWithFilter(e, new SerializeFilter[]{filter}); SpringMVC结合FastJSON定制json返回(过滤某些字段):http://www.aboutchen.org/blog/springmvc-fastjson-property-filter.html

/*

  • 第一种:在对象响应字段前加注解,这样生成的json也不包含该字段。
  • @JSONField(serialize=false)
  • private String name;
    */

/*

  • 第二种:在对象对应字段前面加transient,表示该字段不用序列化,即在生成json的时候就不会包含该字段了。
  • private transient String name;
    */

spring mvc出现 Failed to convert property value of type ‘java.lang.String’ to required type ‘java.util.Date’ for property ‘endtime’:https://www.cnblogs.com/liaojie970/p/5566388.html @InitBinder protected void init(HttpServletRequest request, ServletRequestDataBinder binder) { SimpleDateFormat dateFormat = new SimpleDateFormat(“yyyy-MM-dd”); dateFormat.setLenient(false); binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false)); }

相关链接:

spring framework体系结构及内部各模块jar之间的maven依赖关系

使用Spring中的ExceptionHandlerExceptionResolver进行统一的异常处理