Spring
Spring 是一个轻量级的 IoC / DI 和 AOP 容器的开源框架,致力于构建轻量级的 JavaEE 应用,简化应用开发。前端
IoC 和 DI 思想
IoCjava
将本来在程序中对象的建立权,交由 spring的IoC 容器来管理,强调建立对象。mysql
DIweb
指 Spring 建立对象的过程当中,将对象依赖属性(常量,对象,集合)经过配置设值给该对象。强调设置对象的属性值。面试
Spring项目的建立:
建立Maven项目,添加依赖和插件;
org.springframework
;spring须要经过配置文件
applicationContext.xml
告诉spring
来管理哪些对象;sqlBeanFactory
:表示 Spring IoC 容器 — 生产 bean 对象的工厂,负责配置,建立和管理 bean。数据库文件是Spring Bean Configuration File,文件名通常为:applicationContext.xml;express
在配置文件中完成<bean>标签的配置:经过id和class属性来告诉Spring容器来管理这个对象。apache
从容器中获取这个对象:找到这个配置文件,底层经过反射建立对象,并保存在容器中进行管理;
注入属性:<property>标签来指定对象的属性名的属性值;
测试:经过
BeanFactory
来获取被管理的bean对象;getBean的方法:
类型 变量名 = beanFactory.getBean("配置文件中的name",配置文件的类型.class);
Spring IoC 管理 bean 的原理
经过 Resource 对象加载配置文件;
解析配置文件,解析 bean 元素,id 做为 bean 的名字,class 用于反射获得 bean 的实例,注意:此时,bean 类必须存在一个无参数构造器(和访问权限无关);
调用 getBean 方法的时候,从容器中返回对象实例。
<import resource="文件路径"/>
applicationContext.xml文件中,项目规模变大时,<bean>元素太多,分类分解成多个xml文件,经过<import resource="文件路径"/>
的方式将这些xml文件引入便可。
<import resource="classpath:cn/wolfcode/day1/_02_hello/hello.xml"/>
SpringText
Spring 容器在管理测试代码,节省性能的开销。添加spring-test
的依赖。
@Runwith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
@Autowired
IoC 容器
Spring IoC 容器(Container)
Spring IoC 容器(Container)
应用中,通常不使用 BeanFactory,而推荐使用 ApplicationContext(应用上下文),它继承自BeanFactory,在启动Spring的时候就会把全部的bean都建立好了;
在字段上贴@Autowired注解,能够直接获取到容器中的bean。
bean的做用域:
singleton:单例 ,在 Spring IoC 容器中仅存在一个 bean 实例 (缺省默认的 scope);
prototype:多例 ,每次从容器中调用 Bean 时,都返回一个新的实例,即每次调用 getBean() 时 ,至关于执行 new Xxx():不会在容器启动时建立对象。
注意:
只有正常关闭容器,才会执行 bean 的配置的 destroy-method 方法。
bean 的 scope 为 prototype 的,那么容器只负责建立和初始化,它并不会被 Spring 容器管理(不须要存起来),交给用户本身处理。即 bean 做用域为 prototype 的即便配置了 destroy-method 也不会被调用。
DI
注入方式:
setter方法注入:
setter 方法注入又叫属性注入,但其类必须提供对应 setter 方法。
<property name="对象属性名称" value="须要注入的值"/>
bean注入:
注入 bean,就是把一个 bean(非基本数据类型),经过 setter 方法设置给另外一个 bean;
<property name="对象属性名称" ref="被注入对象的bean的id" />
注入集合:
就是把一个集合类型的数据,经过 setter 方法设置给一个 bean;
配置Druid数据库链接池
使用Spring以前,须要经过DruidDataSource对象来设置链接数据库的四要素才能链接。太麻烦。添加依赖:druid、mysql-connector-java
如今只须要在applicationContext.xml 文件中配置便可:
配置以后:经过注入DruidDataSource对象 . getConnection()
便可得到链接对象。
property-placeholder
配置db.properties,在applicationContext.xml 文件中引入db跑配置文件。
location属性为配置文件的路径;db中配置前缀jdbc.,防止从环境中去获取属性的值。
Autowired 和 Qualifier 注解
共同点:
可让 Spring 自动的把属性或字段须要的对象找出来,并注入到属性上或字段上。
能够贴在字段或者 setter 方法上面。
能够同时注入多个对象。
不一样点:
Autowired 注解寻找 bean 的方式:(先按类型在按名字)
Resource 注解寻找 bean 的方式:(先按名字再按类型)
IoC注解:
简化不少的bean的配置:
@Repository
: 用于标注数据访问组件,即 DAO 组件。@Service
: 用于标注业务层组件。@Controller
: 用于标注控制层组件(如 Struts2 中的 Action,SpringMVC 的 Controller)。@Component
: 泛指组件,当组件很差归类的时候,咱们可使用这个注解进行标注。标注除上其余组件。
须要配置IoC DI注解解析器:让IoC注解或者DI注解起做用,发现某类贴有@Component注解,Spring就会建立这个类的对象存在Spring容器中
贴了注解以后,还须要配置IoC组件扫描器:
<!-- 配置 IoC DI 注解解析器 让Spring帮咱们建立业务对象 -->
<context:component-scan base-package="cn.wolfcode.xxx"/>
静态代理
代理对象彻底包含真实对象,客户端使用的都是代理对象的方法,和真实对象没有直接关系;
代理模式的职责:把不是真实对象该作的事情从真实对象上撇开——职责分离。
缺点:代理类本身实现,项目大,代理类多。
动态代理
动态代理类是在程序运行期间由 JVM 经过反射等机制动态的生成的,因此不存在代理类的字节码文件,动态生成字节码对象,代理对象和真实对象的关系是在程序运行时期才肯定的。
实现选择:
针对有接口:使用 JDK 动态代理;
针对无接口:使用 CGLIB 或 Javassist 组件。
JDK 动态代理
前提
委托类(真实类),必须实现接口。
java.lang.reflect.Proxy 类
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler hanlder)
方法职责:为指定类加载器、一组接口及调用处理器生成动态代理类实例
参数:
loader :类加载器,通常传递真实对象的类加载器
interfaces:代理类须要实现的接口
handler:代理执行处理器,说人话就是生成代理对象帮你要作什么 返回:建立的代理对象
返回:建立的代理对象
java.lang.reflect.InvocationHandler 接口
public Object invoke(Object proxy, Method method, Object[] args)
方法职责:负责集中处理动态代理类上的全部方法调用,让使用者自定义作什么事情,对原来方法加强。
参数:
proxy :生成的代理对象
method:当前调用的真实方法对象
args :当前调用方法的实参
返回:真实方法的返回结果
操做步骤
定义封装事务操做的一个模拟类。
实现
InvocationHandler
接口,实现invoke
方法,实现加强操做。在 Spring 配置文件中配置
InvocationHandler
实现类、事务操做模拟类、真实对象,让其帮咱们建立对象组装依赖。在单元测试类中注入
InvocationHandler
的bean
,在测试方法中手动使用Proxy
建立代理对象,调用代理对象的方法。
调用流程:
CGLIB 动态代理和原理
JDK 动态代理要求真实类必须实现接口。而 CGLIB 与 JDK 动态代理不一样,真实类不用实现接口,代理类会继承真实类。
org.springframework.cglib.proxy.Enhancer//相似 JDK 中 Proxy,用来生成代理类建立代理对象的。
org.springframework.cglib.proxy.InvocationHandler//相似 JDK 中InvocationHandler,让使用者自定义作什么事情,对原来方法加强。
操做步骤
修改
TransactionHandler
实现org.springframework.cglib.proxy.InvocationHandler
接口,其余不变。修改单元测试类中的测试方法,改用
Enhancer
来生成代理类建立代理对象的。
调用流程:
动态代理的选用:
若真实类实现了接口,优先选用 JDK 动态代理。(真实类与代理类是共同实现一个接口)
若真实类没有实现任何接口,使用 Javassit 和 CGLIB 动态代理。(代理类是继承自真实类的)
动态代理问题:对多个 service 对象加强配置太多,还有要手动建立代理对象,在使用时不是面向接口,还要编写 InvocationHandler 接口的实现类。
AOP 思想
AOP(Aspect Oriented Programming),是面向切面编程的技术。
Joinpoint:链接点,通常指须要被加强的方法。where:去哪里作加强。
Pointcut:切入点,哪些包中的哪些类中的哪些方法,可认为是链接点的集合。where:去哪些地方作加强。
Advice:加强,当拦截到 Joinpoint 以后,在方法执行的什么时机(when)作什么样(what)的加强。
Aspect:切面,Pointcut + Advice,去哪些地方 + 在何时 + 作什么加强。
Target:被代理的目标对象。
Weaving:织入,把 Advice 加到 Target 上以后,建立出 Proxy 对象的过程。
Proxy:一个类被 AOP 织入加强后,产生的代理类。
AOP 实现及 Pointcut 表达式
AspectJ 是一个面向切面的框架
AspectJ 切入点语法(表示在哪些包下的哪些类的哪些方法上作切入加强)
execution(* cn.wolfcode.wms.service.*.*(..))
execution(* cn.wolfcode.wms.service.*Service.*(..))
execution(* cn.wolfcode..service.*Service.*(..))
添加依赖:aspectjweaver
配置
<!-- 配置须要加的功能(加强)WHAT -->
<bean id="tx" class="cn.wolfcode.tx.MyTranansationManager"/>
<!-- 配置真实类型的对象 -->
<bean id="employeeService" class="cn.wolfcode.service.impl.EmployeeServiceImpl"/>
<!-- AOP的配置 -->
<aop:config proxy-target-class="true">
<!-- 切面 -->
<aop:aspect ref="tx">
<!-- 定义切入点:WHERE -->
<aop:pointcut expression="execution(* cn.wolfcode.service.impl.*ServiceImpl.*(..))" id="txPointcut"/>
<!-- 切入表达式中的方法,在方法执行以前调用tx.begin() -->
<aop:before method="begin" pointcut-ref="txPointcut"/>
<!-- 切入表达式中的方法,在方法正常执行完后调用tx.commit() -->
<aop:after-returning method="commit" pointcut-ref="txPointcut"/>
<!-- 切入表达式中的方法,在方法执行过程当中出现异常时调用tx.rollback() -->
<aop:after-throwing method="rollback" pointcut-ref="txPointcut"/>
</aop:aspect>
</aop:config>
使用 CGLIB
作以下配置便可:
转帐功能集成:
使用框架,在别人的基础上开发,提升效率;
集成 MyBatis 和业务层,即业务对象、 Mapper 对象等都交由 Spring 容器管理,使用 Spring IoC 和 DI 来完成对象建立及其属性注入,后面再使用 AOP 来配置事务。
依赖及插件:
MyBatis框架所须要的依赖:
mybatis
mybatis-spring
数据库驱动:
mysql-connector-java :SQL链接数据库(做用域:runtime)
数据库链接池:
Druid
druid
日志打印:
slf4j-log4j12
Spring框架:
spring-test:测试(做用域:test)
Spring-jdbc:链接数据库
aspectjweaver :AOP
spring-webmvc :MVC层
web项目共用的:
lombok (做用域:provided)
junit(做用域:test)
javax.servlet-api (做用域:provided)
页面标签:支持 JSTL
taglibs-standard-spec
taglibs-standard-impl
插件:
编译插件:
maven-compiler-plugin
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source><!-- 更新项目(Maven | Update Project)以后,会修改项目的编译版本 -->
<target>1.8</target><!-- 更新项目以后,会修改项目的运行版本 -->
<encoding>utf-8</encoding><!-- 更新项目以后,Java 编译器读取你的文件用的编码 -->
</configuration>
/plugin>服务器maven项目插件:
org.apache.tomcat.maven
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.1</version>
<configuration>
<port>80</port><!-- 端口 -->
<path>/</path> <!-- 上下路径 -->
<uriEncoding>UTF-8</uriEncoding> <!-- 针对 GET 方式乱码处理 -->
</configuration>
</plugin>
配置SqlSessionFactory
使用MyBatis须要建立SqlSessionFactory对象,交给Spring处理。
配置:
配置 Mapper 的代理对象
Mapper接口的实现类让Spring来代理。管理需提供 Mapper 接口(接口中多参数使用@Param注解)和 Mapper XML 文件。
配置业务层对象
编写业务接口和实现类:
配置业务对象:
测试:
注解方式整合 MyBatis
一、配置 Mapper 接口扫描器
以前配置多个Mapper 接口代理对象是比较麻烦的,使用 Mapper 接口扫描器能够批量生成 Mapper 接口代理对象并注册到 Spring 容器中。
二、使用注解方式配置业务对象
在业务类上贴 IoC 注解和 DI 注解:
在 applicationContext.xml 配置文件配置第三方解析程序:
配置总成:
<!-- 配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- 配置数据源 -->
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 配置 IoC DI 注解解析器 让Spring帮咱们建立业务对象 -->
<context:component-scan base-package="cn.wolfcode.ssm.service.impl"/>
<!--
配置时机(相似环绕加强:任什么时候候都能起做用),并关联上面上事务管理器
针对不一样方法能够区分配置
切入点表达式切到的方法,在方法执行以前调用 transactionManager.getTransaction()
切入点表达式切到的方法,在方法执行正常执行完调用 transactionManager.commit()
切入点表达式切到的方法,在方法执行抛出异常时调用 transactionManager.rollback()
-->
<!--CRUD通用事务配置 WHEN-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!--Servlet中查询的方法-->
<tx:method name="get*" read-only="true"/>
<tx:method name="list*" read-only="true"/>
<tx:method name="query*" read-only="true"/>
<tx:method name="count*" read-only="true"/>
<tx:method name="select*" read-only="true"/>
<!--Servlet中非查询的方法-->
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<!-- 配置AOP -->
<aop:config>
<!-- 定义 WHERE -->
<aop:pointcut expression="execution(* cn.wolfcode.ssm.service.impl.*ServiceImpl.*(..))"
id="txPointcut"/>
<!-- WHERE WHEN -->
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>
</aop:config>
<!-- 引入 db.properties:其中保存了链接数据库的四要素 -->
<context:property-placeholder location="classpath:db.properties"/>
<!-- 配置 DataSource 对象:数据源 链接数据库的四要素 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!-- 配置 SqlSessionFactory 对象 -->
<bean id="sqlSessionFactory"
class="org.mybatis.spring.SqlSessionFactoryBean">
<!--
关联 MyBatis :主配置文件
主配置文件 配置能够不配置什么内容,可是约束和根元素必定要保留
若要配置:只须要配置延迟加载、二级缓存
-->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
<!-- 配置别名 -->
<property name="typeAliasesPackage" value="cn.wolfcode.ssm.domain"/>
<!-- 配置数据源:链接数据库 -->
<property name="dataSource" ref="dataSource"/>
<!-- 关联Mapper文件:和Mapper接口编译后位置在一块儿 ,因此能够不配置 -->
<!-- <property name="mapperLocations" value="classpath:cn/wolfcode/ssm/mapper/*Mapper.xml"/> -->
</bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="cn.wolfcode.ssm.mapper"/>
</bean>
</beans>
Spring MVC
MVC框架,它解决Web开发中常见的问题(参数接收、文件上传、表单验证、国际化等),与Spring无缝集成。
Servlet JavaBean JSP,减小耦合,提升可维护性。
前端控制器思想:
Front Controller模式要求在WEB应用系统的前端设置一个入口控制器,是用来提供一个集中的请求处理机制,全部的请求都被发往控制器统一处理,而后把请求分发给各自相应的处理程序,通常用来作一个共同的处理。由于前端控制器集中处理请求的能力,提升了可重用性和可拓展性。
Spring将处理请求的对象称之为处理器/控制器( Controller)。使用MVC框架必须在web.xml中配置前端控制器,通常的,要么是要 Filter,要么是 Servlet。Spring MVC 是基于 Servlet实现的。
添加依赖和插件:
spring-webmvc
、javax.servlet-api
;服务器插件、编译插件;
配置前端控制器:org.springframework.web.servlet.DispatcherServlet
编写处理器类:贴注解@Controller
方法的注解@RequestMapping("/xxx")
编写 Spring MVC 配置文件
处理器Controller
的响应处理
Controller 方法能够有多个不一样类型的参数,以及一个多种类型的返回结果。涉及到经过控制器的方法设计来完成处理请求处理和响应数处理。
响应处理关注的有两方面:
Controller 方法的返回类型;
Controller 共享数据到视图页面。
处理方法返回 ModelAndView:Controller方法中定义 ModelAndView 对象并返回,对象中设置模型数据并指定视图。
消除视图前缀和后缀:配置这个,那么方法最后要找的视图就是:前缀+逻辑视图名+后缀名。
处理方法返回 String
返回 String 类型和共享数据(使用普遍),此时和 Model 参数组合使用。
下面返回值为 String,此时物理视图路径为:前缀+逻辑视图名+后缀。
请求转发:加上forward: 前缀方式,表示请求转发,至关于
request.getRequestDispatcher().forward(request,response)
,转发后浏览器地址栏不变,共享以前请求中的数据。重定向:加上redirect: 前缀方式,表示重定向,至关于
response.sendRedirect()
,重定向后浏览器地址栏变为重定向后的地址,不共享以前请求的数据。使用处理方法的形参来接收请求参数
请求参数名和 Controller方法的形参同名:能够直接接收
请求参数名和 Controller方法的形参不一样名:使用
@RequestParam
注解贴在形参上,设置对应的请求参数名称。请求参数不是必须(用户能够不传该参数):可使用
@RequestParam
的 required 为 false。
乱码处理
get 方式传递中文参数乱码问题:在pom.xml文件的Tomcat插件中设置
post 方法传递中文乱问题:直接使用 Spring MVC 内置的编码过滤器来处理。
处理复合类型请求参数
数组类型参数:多个同类型的请求参数,可直接用数组来接收;
JavaBean 自定义类型参数:注意:请求参数必须和对象的属性同名
@ModelAttribute
注解:@ModelAttribute("xx")
:能够贴在方法和形参上,形参前提是自定义类型,会存到模型里,可在视图中获取到。
若没贴这个注解,则经过类型首字母小写做为 key 获取;
若贴了这个注解,能够自定义 key,再经过这个 key 获取。
日期类型处理
前台日后台传参转换为 Date 类型:在对象字段或 Controller 形参贴上 @DateTimeFormat
在 JSP 中显示 Date 类型的数据,此时须要使用 fmt 标签。添加依赖才能支持 JSTL。
taglibs-standard-spec
、taglibs-standard-impl
Spring MVC 文件上传
依赖:commons-fileupload
上传表单:注意请求的类型必须是:multipart/form-data,且是 POST。
配置上传解析器:注意上传解析器这个 bean 名称是固定的,必须为 multipartResolver。
上传控制器:接收上传文件,并把上传的文件拷贝项目的根路径下指定目录,文件名随机(防止文件覆盖)。
核心组件分析
一、核心组件
前端控制器 DispatcherServlet
不须要咱们开发,由框架提供,须要在 web.xml 中配置。做用:接受请求,处理响应结果,转发器,中央处理器。
处理器映射器 HandlerMapping
不须要咱们开发,由框架提供。做用,更具请求的 URL 找到对应的 Handler。
处理器适配器 HandlerAdapter
不要咱们开发,由框架提供。做用:调用处理器(Handler / Controller)的方法。
处理器 Handler(又名 Controller),后端控制器
须要咱们开发,必须按照 HandlerAdapter 的规范去开发。做用:接收用户请求数据,调用业务方法处理请求。
视图解析器 ViewResolver
不须要咱们开发,有框架或者第三方提供。做用:视图解析,把逻辑视图名称解析成真正的物理视图。支持多种视图技术 Velocity、FreeMarker、JSP 等。
视图
须要咱们开发。做用:把数据展示给用户。
开发步骤:
配置前端控制器
配置处理器映射器、处理适配器、视图解析器(用默认的可不配置)。
须要开发(结合需求):
先开发 Contoller,再配置。
开发 JSP。
执行流程分析
一、图示流程
二、文字描述
用户发送出请求到前端控制器 DispatcherServlet。
DispatcherServlet 收到请求调用 HandlerMapping(处理器映射器)。
HandlerMapping 找到具体的处理器(经过 XML 或注解配置),生成处理器对象及处理器拦截器(如有),再一块儿返回给 DispatcherServlet。
DispatcherServlet 调用 HandlerAdapter(处理器适配器)。
HandlerAdapter 通过适配调用具体的处理器的某个方法(Handler/Controller)。
Controller 执行完成返回 ModelAndView 对象。
HandlerAdapter 将 Controller 返回的 ModelAndView 再返回给 DispatcherServlet。
DispatcherServlet 将 ModelAndView 传给 ViewReslover(视图解析器)。
ViewReslover 解析后返回具体 View(视图)。
DispatcherServlet 根据 View 进行渲染视图(即将模型数据填充至视图中)。
DispatcherServlet 响应用户。
解耦,责任分离,可替换实现。看源码分析执行流程。
小伙砸,欢迎再看分享给其余小伙伴!共同进步!
本文分享自微信公众号 - java学途(javaxty)。
若有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一块儿分享。