本节开始进入ssm框架(Spring、SpringMVC、Mybatis),并过渡到springboot当中。由于博主都是在springboot中集成ssm框架,因此,接下来对ssm的介绍,不会涉及到它们单独的环境搭建,而是在springboot学习中统一搭建。
本节前半部分是对郭永峰老师的spring教学的总结,后部分结合雷丰阳老师的Spring注解驱动开发进行记录总结。
在此顺便推荐一下雷丰阳老师的视频,老师对源码的解读让我受益匪浅。
Spring是一个开源框架,Spring是于2003 年兴起的一个轻量级的Java 开发框架,由Rod Johnson 在其著作Expert One-On-One J2EE Development and Design中阐述的部分理念和原型衍生而来。它是为了解决企业应用开发的复杂性而创建的。 Spring使用基本的JavaBean来完成以前只可能由EJB完成的事情。然而,Spring的用途不仅限于服务器端的开发。从简单性、可测试性和松耦合的角度而言,任何Java应用都可以从Spring中受益
简单来说: Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架。
什么是IOC? 一般来说,对象都是由程序员写出来,程序员new出来,程序员销毁。 如果把对象的控制权(尤指Javabean)交给Spring框架,这就是“控制反转”。 由Spring为我们创建所有对象创建,维护对象依赖关系。
什么是AOP? Aspect Oriented Programming,面向切面编程 我们学习过面向过程编程和面向对象编程,同理,面向切面编程也是一种编程方式。 一般来说,程序都是“自上而下”编写、生效的。如果我们“横插一脚”,将代码切进去使其生效,这就是面向切面。 具体实现原理请往后看。
方便解耦,简化开发:
AOP编程的支持:
声明式事务的支持:
方便程序的测试:
方便集成各种优秀框架:
降低JavaEE API的使用难度
Spring 框架是一个分层架构,它包含一系列的功能要素并被分为大约20个模块。这些模块分为Core Container、Data Access/Integration、Web、AOP(Aspect Oriented Programming)、Instrumentation和测试部分,如下图所示:
Spring将横穿整个项目
目标: 掌握web中集成Spring需要哪些包 掌握IOC是什么
流程:
spring-core 包含Spring框架基本的核心工具类,Spring其它组件要都要使用到这个包里的类,是其它组件的基本核心。 spring-beans 所有应用都要用到的,它包含访问配置文件、创建和管理bean 以及进行Inversion of Control(IoC) / Dependency Injection(DI)操作相关的所有类 spring-context Spring提供在基础IoC功能上的扩展服务,此外还提供许多企业级服务的支持, 如邮件服务、任务调度、JNDI定位、EJB集成、远程访问、缓存以及各种视图层框架的封装等。 spring-expression Spring表达式语言 com.springsource.org.apache.commons.logging 第三方的主要用于处理日志
看似使用复杂,但是这是为了让初学者了解过程,实际使用中都是直接通过注解注入,下文第六节会有讲解。
上一节展示了通过spring创建对象,本节展示通过spring实现相关依赖注入(Dependency Injection)。
什么是依赖注入? 当我创建A的时候,A需要用到B,此时,Spring也会自动将B创建。这就是注入相关依赖。“依赖注入”不仅仅是注入对象,属性方法等等都可注入。
创建一个UserService,提供get/set方法(注入属性,Spring会自动调用get/set方法)
xml中配置注入。
xml中的
<bean id="userId" class="com.web.User"> </bean>
相当于告诉Spring进行
User user = new User();
xml中的
<bean id="userId" class="com.web.User">
<property name="name" value="shunxu"><property>
</bean\>
相当于告诉Spring进行
User user = new User();
user.setName("shunxu");
ApplicationContext context =
new ClassPathXmlApplicationContext("beans.xml");
//path为beans.xml的绝对路径
BeanFactory factory = new XmlBeanFactory(new FileSystemResource(path));
User user = (User) factory.get("userId");
一般只用ApplicationContext ,但是BeanFactory在底层源码中被大量使用,也需要了解。
全局使用
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
底层原理通过new实现
xml配置文件
<bean id="userId" class="com.web.User">
<property name="name" value="shunxu"><property>
</bean\>
Java代码
//new 对象
User user = (user ) context.getBean("user Id");
需要准备一个工厂类 UserFactory,并提供创建方法createUser
<bean id="userId" class="com.web.UserFactory" factory-method="createUser"></bean>
User user = UserFactory.createUser();
实际上还是跟第一种一样,只不过是通过Spring创建了工厂,然后利用工厂创建的对象。
同样得先自己写一个bean工厂
<bean id="factory" class="com.web.UserFactory2"></bean>
<bean id="userId" factory-bean="factory" factory-method="createUser"></bean>
UserFactory2 factory = new UserFactory2 ();
User user = factory2.createUser();
只需要记住:Spring提供了对自定义bean工厂的配置支持
类别 | 说明 |
---|---|
singleton | 在Spring IoC容器中仅存在一个Bean实例,Bean以单例方式存在,默认值 |
prototype | 每次从容器中调用Bean时,都返回一个新的实例,即每次调用getBean()时 ,相当于执行new XxxBean() |
request | 每次HTTP请求都会创建一个新的Bean,该作用域仅适用于WebApplicationContext环境 |
session | 同一个HTTP Session 共享一个Bean,不同Session使用不同Bean,仅适用于WebApplicationContext 环境 |
globalSession | 一般用于Portlet应用环境,该作用域仅适用于WebApplicationContext 环境 |
只需要掌握第一第二个,后面三个了解即可。
SpEL就是Spring专属的语言 目前可能用不上,在springboot中有时候会用
#{123}、#{‘jack’} : 数字、字符串 #{beanId} :另一个bean引用 #{beanId.propName} :操作数据 #{beanId.toString()} :执行方法 #{T(类).字段|方法} :静态方法或字段
初学者做到能看懂下图即可
本节对阅读Spring系列源码的能力影响较大,可以的话,多花点时间理解上述过程。
以下代码仅供参考,不要全抄。 按照自己的项目名进行改写。
注:xml中的注入方式比较繁琐,一般都是通过注解注入。 xml中的集合注入方式,有兴趣的可以百度,在此不多赘述。
实际开发中,一般不写bean.xml,而是直接通过Spring注解实现注入
@Component(“id”)
3个@Component注解衍生注解(功能一样)取代<bean class="">
依赖注入
自定义初始化
自定义销毁
相当于配置装载好了UserServiceImpl,此时直接通过bean工厂拿到即可使用
对于需要new对象的地方,都通过Autowired实现自动注入(前提是你以及将该对象加入bean容器中,即:该对象被@Component、@Controller、@Service、@Repository)
使用Qualifier的话,上面还得加上Autowired,双层注解才生效
掌握以上的注解基本就够用了,具体的内容可查看文末:Spring注解驱动开发
AOP为Aspect Oriented Programming的缩写; 意为:面向切面编程。 这是一种通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。
AOP是OOP(面向对象编程)的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。
利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
AOP采取横向抽取机制,取代了传统纵向继承体系重复性代码
经典应用:
Spring AOP使用纯Java实现,不需要专门的编译过程和类加载器,在运行期通过代理方式向目标类织入增强代码
AspectJ是一个基于Java语言的AOP框架,Spring2.0开始,Spring AOP引入对Aspect的支持,AspectJ扩展了Java语言,提供了一个专门的编译器,在编译时提供横向代码的织入
aop底层将采用代理机制进行实现。
有接口用jdk动态代理,无接口用cglib
现在看不懂没关系,接触多了就看懂了。 以上是定义,下面博主给出自己的理解
AOP能够“对方法横切一刀”,添加额外的方法。 现在假设有个类A,在com.web包下,其中有个printA方法。
aspectj 通知类型,只定义类型名称,以及方法格式。 个数:
环绕通知,必须手动执行目标方法 try{ //前置通知 //执行目标方法 //后置通知 } catch(){ //抛出异常通知 }
以下包的版本比较老了,请自行在maven仓库中选择合适版本
开启注解配置(包名改成自己的切面类所在包)
预备知识
这个暂时学会模仿使用即可
@Pointcut(“execution(public * xyz.shuxu.controller….(…))”) 用于定义切入点, 以下符号按顺序进行解释:
之所以写一个空方法并定义切入点,是为了后面方便引用
@Aspect
@Component
public class TestAspect {
/**
* 定义切入点,切入点为xyz.shunxu.controller下的所有函数
*/
@Pointcut("execution(public * xyz.shuxu.controller..*.*(..))")
public void webPointcut(){}
/**
* 前置通知:在连接点之前执行的通知
* @param joinPoint
* @throws Throwable
*/
@Before("webPointcut()")
public void doBefore(JoinPoint joinPoint) throws Throwable {
System.out.println("前置通知");
}
@AfterReturning(returning = "ret",pointcut = "webPointcut()")
public void doAfterReturning(Object ret) throws Throwable {
System.out.println("后置通知");
System.out.println("处理完请求,返回内容:" +ret);
}
@Around(value="webPointcut()")
public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("环绕通知前-");
Object object = joinPoint.proceed();
System.out.println("环绕通知后-");
return object;
}
@AfterThrowing(value = "webPointcut()",throwing = "e")
public void doArterThrowing(JoinPoint joinPoint,Throwable e){
System.out.println("异常通知"+e.getMessage());
}
@After(value = "webPointcut()")
public void doAfter(){
System.out.println("最终通知");
}
}
上述代码是我直接从springboot项目中改写过来的,可能不能正常使用。。。可能还需要在xml中配置,详情请复制报错信息百度
运行xyz.shuxu.controller下的任意一个方法,就可以看到效果。
这就是所谓的“横切一刀”,没有对原有代码做任何改变,但是却能够“更改”它。
execution() (重点掌握) 用于描述方法 语法:execution(修饰符 返回值 包.类.方法名(参数) throws异常)
within: 匹配包或子包中的方法(了解) within(com.test.aop…*)
this: 匹配实现接口的代理对象中的方法(了解) this(com.test.aop.user.UserDAO)
target: 匹配实现接口的目标对象中的方法(了解) target(com.test.aop.user.UserDAO)
args: 匹配参数格式符合标准的方法(了解) args(int,int)
bean(id) 对指定的bean所有的方法(了解) bean(‘userServiceId’)
下图是我学习雷丰阳老师视频的整理,老师的视频中只有简单的框架。
图片保存后放大可高清查看
本节只总结理论基础,方便后面学习Springboot
transaction就是事务,缩写为tx 因此Spring的事务jar包为 spring-tx-版本号.jar
注:DataSourceTransactionManager是JDBC事务管理器,其他的管理器可见名知意。
下表用于事务配置,目前能够看懂表即可
关键字 | 描述 | 解释 |
---|---|---|
PROPAGATION_REQUIRED | required , 必须 【默认值】 | 支持当前事务,A如果有事务,B将使用该事务。如果A没有事务,B将创建一个新的事务。 |
PROPAGATION_SUPPORTS | supports,支持 | 支持当前事务,A如果有事务,B将使用该事务。如果A没有事务,B将以非事务执行。 |
PROPAGATION_MANDATORY | mandatory ,强制 | 支持当前事务,A如果有事务,B将使用该事务。如果A没有事务,B将抛异常。 |
PROPAGATION_REQUIRES_NEW | requires_new ,必须新的 | 如果A有事务,将A的事务挂起,B创建一个新的事务。 如果A没有事务,B创建一个新的事务 |
PROPAGATION_NOT_SUPPORTED | not_supported ,不支持 | 如果A有事务,将A的事务挂起,B将以非事务执行。如果A没有事务,B将以非事务执行 |
PROPAGATION_NEVER | never,从不 | 如果A有事务,B将抛异常。如果A没有事务,B将以非事务执行 |
PROPAGATION_NESTED | nested ,嵌套 | A和B底层采用保存点机制,形成嵌套事务。 |
掌握:PROPAGATION_REQUIRED、PROPAGATION_REQUIRES_NEW、PROPAGATION_NESTED