admin管理员组文章数量:1794759
万字Spring框架学习总结(附核心代码详细注释)
Spring学习笔记总结
学习视频地址:动力节点视频
1.Spring概述 1.1Spring框架是什么?Spring框架是一个开放源代码的J2EE应用程序框架,由[Rod Johnson](baike.baidu/item/Rod Johnson/1423612)发起,是针对bean的生命周期进行管理的轻量级容器(lightweight container)。 Spring解决了开发者在J2EE开发中遇到的许多常见的问题,提供了功能强大IOC、AOP及Web MVC等功能。Spring可以单独应用于构筑应用程序,也可以和Struts、Webwork、Tapestry等众多Web框架组合使用,并且可以与 Swing等桌面应用程序AP组合。因此, Spring不仅仅能应用于J2EE应用程序之中,也可以应用于桌面应用程序以及小应用程序之中。Spring框架主要由七部分组成,分别是 Spring Core、 Spring AOP、 Spring ORM、 Spring DAO、Spring Context、 Spring Web和 Spring Web MVC。
轻量
spring框架使用的jar比较小,都在1M一下或者几百kb。spring核心功能的所需的jar总共在3M左右。spring框架运行时占用的资源少,运行效率高,不依赖别的jar。
针对接口编程,解耦合
spring提供了Ioc控制反转,由容器管理对象,对象的依赖关系。原来在程序代码中的对象创建方式,现状由容器完成。对象之间的依赖解耦合。
AOP编程的支持
通过Spring提供的AOP功能,方便进行面向切面的编程,许多不容易用传统0OP实现的功能可以通过AOP轻松应付,在Spring中,开发人员可以从繁杂的事务管理代码中解脱出来,通过声明式方式灵活地进行事务的管理,提高开发效率和质量。
方便集成各种优秀的框架
Spring不排斥各种优秀的开源框架,相反Spring可以降低各种框架的使用难度,Spring提供了对各种优秀框架( 如Struts,Hibernate、MyBatis) 等的直接支持。简化框架的使用。Spring像插线板一样, 其他框架是插头,可以容易的组合到一起。需要使用哪个框架,就把这个插头放入插线板。不需要可以轻易的移除。
控制反转(Ioc,Inversion of Control),是一个概念,一种思想。指将传统上由程序代码直接操控的对象调用权交给容器,通过容器来实现对象的装配和管理。控制反转就是对对象控制权的转移,从程序代码本身反转到了外部容器。通过容器实现对象的创建,属性赋值,依赖的管理。
IoC是一个概念,是一种思想,其实现方式多种多样。当前比较流行的实现方式是依赖注入。应用广泛。 依赖: classA 类中含有classB的实例,在classA中调用classB的方法完成功能,即classA对classB有依赖。 loc的实现: ➢依赖注入: DI(Dependency Injection),程序代码不做定位查询,这些工作由容器自行完成。 依赖注入DI是指程序运行过程中,若需要调用另一个对象协助时,无须在代码中创建被调用者,而是依赖于外部容器,由外部容器创建后传递给程序。
Spring的依赖注入对调用者与被调用者几乎没有任何要求,完全支持对象之间依赖关系的管理。 Spring框架使用依赖注入(DI) 实现IoC。 Spring容器是一个超级大工厂,负责创建、管理所有的Java对象,这些Java对象被称为Bean。Spring 容器管理着容器中Bean之间的依赖关系,Spring 使用“依赖注入”的方式来管理Bean之间的依赖关系。使用loC实现对象之间的解耦合。
2.1开发工具准备利用maven工具,创建
实现步骤: 1.创建maven项目 2.加入maven的依赖 spring的依赖,版本5.3.7 junit依赖 3.创建类(接口和它的实现类),和没有使用框架一样,就是普通的类。 4.创建spring需要使用的配置文件 声明类的信。这些类由spring创建和管理 5.测试spring创建的对象。 2.2Sprig的第一个程序 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="www.springframework/schema/beans" xmlns:xsi="www.w3/2001/XMLSchema-instance" xsi:schemaLocation="www.springframework/schema/beans www.springframework/schema/beans/spring-beans.xsd"> <!--告诉spring创建对象 声明bean,告诉spring要创建某个类的对象 id是对象的自定义名称(唯一值)。spring通过这个名称找到对象 class:类的全限定名称(不能是接口,因为spring是反射机制) spring就完成SomeService someService = new SomeServiceImpl(); spring是把创建好的对象放到了map中,spring框架中有一个map存放对象的。 springMap.put(id的值,对象) 例如 springMap.put("someService",new someServiceImpl()); 一个bean标签只声明一个对象 --> <bean id="someService" class="cqutlc.service.Impl.someServiceImpl"></bean> <!--spring能创建一个非自定义的类--> <bean id="mydate" class="java.util.Date"/> </beans> <!--spring的配置文件 1.beans是根标签,spring中把Java对象成为bean 2.spring-beans.xsd是约束文件,和mybatis指定的类似 --> package cqutlc; import cqutlc.service.Impl.someServiceImpl; import cqutlc.service.someService; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Test1 { @Test public void test1(){ someService someService=new someServiceImpl(); someService.doSome(); } /*spring默认创建对象的时间:在创建spring的容器时,他会创建配置文件中的所有对象*/ @Test public void test2(){ //使用spring容器创建的对象 //1.指定spring配置文件的名称 String config="beans.xml"; //2.创建表示spring容器的对象,ApplicationContext //ClassPathXmlApplicationContext;表示从类路径中加载spring的配置文件 ApplicationContext ac=new ClassPathXmlApplicationContext(config); //3.从容器中获取某个对象,你要调用对象的方法, //getBean("配置文件中的bena的id值"); someService service=(someService)ac.getBean("someService"); //使用spring创建好的对象 service.doSome(); } /*获取spring容器中的Java对象的信*/ @Test public void test3(){ String config="beans.xml"; ApplicationContext ac=new ClassPathXmlApplicationContext(config); //使用spring提供的方法,获取容器中定义的对象的数量 int num=ac.getBeanDefinitionCount(); System.out.println(num); //容器中每个定义的对象的名称 String[] names= ac.getBeanDefinitionNames(); for (String name : names) { System.out.println(name); } } } 2.3基于XML的DI在spring配置文件中,给Java对象的属性赋值。
di:依赖注入,表示创建对象,给属性赋值。
di的实现语法: 1.在spring配置文件中,使用标签和属性完成,叫做基于xml的di实现 2.使用spring中的注解进行属性的赋值,叫做基于注解的di实现。
di的语法分类 1.set注入(设置注入): spring调用类的set方法,在set方法可以实现属性的赋值
2.构造注入,spring调用类的有参构造方法,创建对象。在构造方法中完成赋值。
set注入实例分析
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="www.springframework/schema/beans" xmlns:xsi="www.w3/2001/XMLSchema-instance" xsi:schemaLocation="www.springframework/schema/beans www.springframework/schema/beans/spring-beans.xsd"> <!--声明student对象 注入:就是赋值的意思 简单类型:spring中规定Java的基本数据类型和string类型都是简单类型。 di:给属性赋值 1.set注入(设置注入):spring调用类的set方法,你可以在set方法中完成属性赋值 利用property --> <bean id="student" class="cqutlc.ba01.Student"> <property name="name" value="李四"/><!--调用setName...--> <property name="age" value="20"/>认准set方法 </bean> </beans>当属性为引用类型时
2.引用类型的set注入:spring调用set方法 --> <bean id="student" class="cqutlc.ba02.Student"> <property name="name" value="李四"/><!--调用setName...--> <property name="age" value="24"/> <property name="school" ref="school"/> </bean> <bean id="school" class="cqutlc.ba02.School"> <property name="name" value="cqut"/> <property name="address" value="cq"/> </bean>构造注入
得有构造参数
2.构造注入 spring调用类的有参数构造方法,在创建对象的同时给属性赋值 构造注入使用 --> <bean id="student" class="cqutlc.ba03.Student"> <constructor-arg name="name" value="lc"/> <constructor-arg name="age" value="19"/> <constructor-arg name="school" ref="myschool"/> </bean> <bean id="myschool" class="cqutlc.ba03.School"> <property name="name" value="cqut"/> <property name="address" value="cq"/> </bean>引用类型的自动注入
byName和byType
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="www.springframework/schema/beans" xmlns:xsi="www.w3/2001/XMLSchema-instance" xsi:schemaLocation="www.springframework/schema/beans www.springframework/schema/beans/spring-beans.xsd"> <!-- 引用类型的自动注入:spring框架根据某些规则可以给引用类型赋值。不用你再给引用类型赋值了 使用的规则常用的是 1.byName(按名称注入):Java类中引用类型的属性名和spring容器中(配置文件)<bean>的id名称一样。 且数据类型一致,这样的容器中的bean,spring能够赋值给引用类型。 2.byType(按类型注入):Java类中引用类型的数据类型和spring容器中(配置文件)<bean>的class是同源关系。 <bean id="" class="" outowire="byType"> --> <bean id="student" class="cqutlc.ba04.Student" autowire="byName"> <property name="name" value="李四"/><!--调用setName...--> <property name="age" value="24"/> <!--<property name="school" ref="school"/>--> </bean> <bean id="school" class="cqutlc.ba04.School"> <property name="name" value="cqut"/> <property name="address" value="cq"/> </bean> </beans>多个配置文件的优势
1.每个文件的大小比一个文件要小得多。效率高
2.避免多人竞争带来的冲突
多文件的分配方式:
1.按功能模块,一个模块一个配置文件。
2.按类的功能,数据库相关,做事务处理的,做service的。
包含关系的配置路径
2.4基于注解的DI通过注解完成Java对象的创建,属性赋值
使用注解的步骤
加入maven的依赖spring-context,在你加入spring-context的同时,间接加入spring-aop的依赖。
使用注解必须使用spring-aop依赖
在类中加入spring的注解(多个不同功能的注解)
在spring的配置文件中,加入一个组件扫描器的标签,说明注解在你的项目中的位置。
学习的注解有:
1.@Component 2.@Repository 3.@Service 4.@Controller 5.@Value 6.@Autowired 7.@Resource
简单类型
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="www.springframework/schema/beans" xmlns:xsi="www.w3/2001/XMLSchema-instance" xmlns:context="www.springframework/schema/context" xsi:schemaLocation="www.springframework/schema/beans www.springframework/schema/beans/spring-beans.xsd www.springframework/schema/context www.springframework/schema/context/spring-context.xsd"> <!--声明组件扫描器(component-scan), 组件就是Java对象,所以就是找Java对象 base-package:指定注解在你的项目中的包名 component-scan工作方式:spring会扫描遍历base-package指定的包 把包中和子包中的所有类,找到类中的注解,按照注解的功能创建对象和给属性赋值。 --> <context:component-scan base-package="cqutlc.ba01"/> </beans> package cqutlc.ba01; import org.springframework.stereotype.Component; /* * @Component:创建对象的,等同于<bean>的功能 * 属性value: 就是对象的名称,也就是bean的id值,value值是唯一的,创建的对象在整个spring容器中就一个 * 位置:在类的上面写注解 * */ //等同于<bean id="myStudent" class="cqutlc.ba01.Student"/> //@Component(value = "myStudent") //省略value //@Component("myStudent") //不指定对象名称,由spring提供默认名称(首字母小写类名) @Component public class Student { private String name; private Integer age; public void setName (String name) { this.name = name; } public void setAge (Integer age) { this.age = age; } @Override public String toString () { return "Student{" + "name='" + name + '\\'' + ", age=" + age + '}'; } } package cqutlc; import cqutlc.ba01.Student; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class test1 { @Test public void test(){ String config="applicationContext.xml"; ApplicationContext ac=new ClassPathXmlApplicationContext (config); //从容器中获取对象 Student student=(Student) ac.getBean ("student"); System.out.println (student); } } * spring中和@Component功能一致,创建对象的注解还有: * @Repository(用在持久层上):放在dao的实现类上面, * 表示创建dao对象,dao对象是能访问数据库的。(持久层注解) * * @Service(用在业务层类的上面):放在service的实现类上面, * 创建service对象,service对象是做业务处理的,可以有事物等功能的。 * * @Controller(用在控制器的上面):放在控制器(处理器)类的上面,创建控制器对象的, * 控制器对象可以接收用户提交的参数和显示请求的处理结果。 * * 以上三个注解的使用语法和@Component是一样的,都能够创建对象,但是这三个注解还有额外的功能----给项目分层指定多个包的三种方式
引用类型
@Autowired:spring框架提供的注解,实现引用类型的赋值 spring中通过注解给引用类型赋值,使用的是自动注入,支持byName和byType @Autowired默认使用@byType自动注入 位置:1.在属性定义的上面,无需set方法,推荐使用。被引用的类必须提前利用@Component注解标识。 2.在set方法的上面 属性:required,是一个boolean类型的,默认是true,表示引用类型失败时,程序报错并终止运行。要是false则正常运行,赋值为null
最好用true,可以及时发现错误!
如果要使用byName的方式 1.在属性的上面加上@Autowired 2.在属性上面加入@Qualifier(vlaue=“bean的id”):表示使用指定名字的bean完成赋值。
@Resource:来自于JDK中的注解,spring框架提供了对这个注解功能的支持。可以用它给引用类型赋值,使用的也是自动注入原理,支持byName,byType。默认是byName
位置: 1.在属性定义的上面,无需set方法,推荐使用
2.在set方法的上面 先使用byName自动注入,假如失败了就会再使用byType
如何只使用byName? 需要新增加一个属性name name的值为bean的id名称
3.AOP面向切面编程 3.1动态代理 动态代理是指:程序在整个运行过程中根本就不存在目标类的代理类,目标对象的代理只是由代理生成工具(不是真实定义的类)在程序运行时由JVM根据反射等机制动态生成,代理对象与目标对象的代理关系在程序运行时确定。
实现方式:
jdk动态代理, 使用jdk中的Proxy, Method, Invocai tonHanderl创建代理对象。jdk动态代理要求目标类必须实现接口。 cglib动态代理:第三方的工具库,创建代理对象,原理是继承。通过继承目标类,创建子类。子类就是代理对象。要求目标类不能是final的,方法也不能是final的。
动态代理的作用:
AOP (Aspect Orient Programming),面向切面编程。面向切面编程是从动态角度考虑程序运行过程。
AOP底层,就是采用动态代理模式实现的。采用了两种代理: JDK的动态代理,与CGLIB的动态代理。
AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,可通过运行期动态代理实现程序功能的统一维护的一种技术。AOP是Spring框架中的一个重要内容。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。(动态代理的规范化,把动态代理的实现步骤,方式都定义好了,让开发人员用一种统一的方法,使用动态代理)。
切面:给你的目标类增加的功能,就是切面,什么日志等(切面的特点:一般都是非业务方法,独立使用的。)
面向切面编程,就是将交叉业务逻辑封装成切面,利用AOP容器的功能将切面织入到主业务逻辑中。所谓交叉业务逻辑是指,通用的、与主业务逻辑无关的代码,如安全检查、事务、日志、缓存等。 若不使用AOP,则会出现代码纠缠,即交叉业务逻辑与主业务逻辑混合在一起。这样,会使主业务逻辑变的混杂不清。
如何理解面向切面编程?
一个切面有三个关键的要素:
aop的实现
aop是一个规范,是一个动态的一个规范化,一个标准。
aop的技术实现框架:
1.spring:spring在内部实现了aop规范,能做aop的工作。
2.aspectJ:一个开源的专门做aop的框架。spring框架中集成了aspectJ框架,通过spring就可以使用aspectJ的功能了。
aspectJ框架实现有两种方式:1.使用xml的配置文件(配置全局事务) 2.使用注解,一般都用注解
3.5学习AspectJ框架的使用 如何表示切面的执行时间?注解表示:1.@Before 2.@AfterReturning 3.@Around 4.@AfterThrowing 5.@After
如何表示切面执行的位置?使用的是切入点表达式。
表达式原型为:
execution(modifiers-pattern? ret-type-pattern declaring-type-pattern?name-pattern(param-pattern) throws-pattern?)解释:
modifiers-pattern 访问权限类型
ret-type-pattern 返回值类型
declaring-type-pattern 包名类名
name-pattern(param-pattern) 方法名(参数类型和参数个数)
throws-pattern 抛出异常类型
?表示可选部分
以上表达式共分为四个部分 execution(访问权限 方法返回值 方法声明(参数)异常类型)
切入点表达式要匹配的对象就是目标方法的方法名。所以,execution 表达式中明显就是方法的签名。注意,表达式中黑色文字表示可省略部分,各部分间用空格分开。在其中可以使用以下符号:
Aspect的开发环境 使用aspectJ框架实现aop 使用aop:目的是给已经存在的一些类和方法,增加额外的功能,前提是不改变原来的类的代码。 框架的使用步骤: 1.新建maven项目 2.加入依赖 spring依赖 aspectJ依赖 junit单元测试 3.创建目标类:接口和他的实现类 要做的是给类中的方法去增加功能 4.创建切面类:普通类 1.在类的上面加入@Aspect 2.在类中去定义方法---要执行的功能代码 3.在方法的上面加入aspectJ中的通知注解,例如@Before 还需要指定切入点表达式execution() 5.创建spring的配置文件,在文件中声明对象,把对象交给容器统一管理 声明对象可以使用注解或者xml配置文件 声明目标对象 声明切面类对象 声明aspectJ框架中的自动代理生成器标签(用来完成代理对象的自动创建功能的) 6.创建测试类,从spring容器中获取目标对象(实际上是代理对象)。 通过代理执行方法,实现aop的功能增强@Before实现的一个例子
package cqutlc.ba01; public interface SomeSevice { void doSome(String name,Integer age); } package cqutlc.ba01; //目标类 public class SomeSeviceImpl implements SomeSevice { @Override public void doSome (String name, Integer age) { //给doSome方法增加一个功能,在doSome方法执行之前,输出方法的执行时间 System.out.println ("目标方法执行"); } } package cqutlc.ba01; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import java.util.Date; /* * @Aspect:aspectJ框架中的注解,用来表示当前类是切面类 * 位置:类定义的上面 * */ @Aspect public class MyAspect { /* * 定义方法:实现切面功能的、 * 方法的定义要求: * 1.公共方法 * 2.没有返回值3.方法名自定义4.方法可以有参数也可以没有参数,有几个参数类型可以使用() * */ /*@Before 前置通知注解 * 属性:value,切入点表达式,表示切面的功能执行的位置 * 特点:在目标方法之前先执行,不会改变目标方法的执行结果,不会影响目标方法的执行 * */ @Before (value = "execution(public void *..SomeSeviceImpl.doSome(..))") public void myBefore(){ //功能代码 System.out.println ("时间:"+new Date ()); } } <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="www.springframework/schema/beans" xmlns:xsi="www.w3/2001/XMLSchema-instance" xmlns:aop="www.springframework/schema/aop" xsi:schemaLocation="www.springframework/schema/beans www.springframework/schema/beans/spring-beans.xsd www.springframework/schema/aop www.springframework/schema/aop/spring-aop.xsd"> <!--把对象交给spring容器,由容器统一创建和管理对象--> <!--声明目标对象--> <bean id="someService" class="cqutlc.ba01.SomeSeviceImpl"/> <!--声明切面类对象--> <bean id="myAspect" class="cqutlc.ba01.MyAspect"/> <!--声明自动代理生成器:使用aspectJ框架内部的功能,创建目标对象的代理对象 创建代理对象是在内存中实现的,修改目标对象的内存中的结构,创建为代理对象 所以目标对象就是被修改后的代理对象 aspectj-autoproxy:会把spring容器中的所有的目标对象,一次性都生成代理对象。 --> <aop:aspectj-autoproxy/> </beans> package cqutlc.ba01; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class test1 { @Test public void test1(){ String config="applicationContext.xml"; ApplicationContext ac=new ClassPathXmlApplicationContext (config); SomeSevice proxy=(SomeSevice)ac.getBean ("someService"); //通过代理的对象执行方法,实现目标方法执行时,增强了功能。 proxy.doSome ("lisi",20); } }JoinPoint
指定通知方法中的参数
joinpoint:业务方法,要加入切面功能的业务方法
作用是:可以在通知方法中获取方法执行时的信,例如,方法名称,方法的实参。
如果你的切面功能中需要用到方法的信,就加入joinpoint
这个joinpoint参数的值是由框架赋予,必须是第一个位置的参数。
@Aspect public class MyAspect { @Before (value = "execution(public void *..SomeSeviceImpl.doSome(..))") public void myBefore(JoinPoint jp){ //获取方法的完整定义 System.out.println("方法的定义:"+jp.getSignature()); System.out.println("方法的名称:"+jp.getSignature().getName()); //获取方法的实参 Object[] args= jp.getArgs(); for(Object arg: args){ System.out.println("参数="+arg); } //功能代码 System.out.println ("时间:"+new Date ()); } }@AfterReturning
package cqutlc.ba02; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import java.util.Date; /* * @Aspect:aspectJ框架中的注解,用来表示当前类是切面类 * 位置:类定义的上面 * */ @Aspect public class MyAspect { /* * 后置通知定义方法:实现切面功能的、 * 方法的定义要求: * 1.公共方法 * 2.没有返回值3.方法名自定义4.方法有参数,推荐使用object,参数名自定义 * */ /* * @AfterReturning * 属性: * 1.value:切入点表达式 * 2.returning:自定义的变量,用来表示目标方法的返回值,自定义变量名必须和通知方法的形参名一样 * 特点: * 1.在目标方法之后执行的 * 2.能够获得目标方法的返回值,可以根据这个返回值做不同的处理功能 * Object res = doOther(); * 3.可以修改这个返回值。 * */ @AfterReturning(value = "execution(* *..SomeSeviceImpl.doOther(..))", returning = "res") public void myAfterReturing(Object res){ //Object res :是目标方法执行后的返回值,根据返回值做你的切面的功能处理 System.out.println ("后置通知,获取的返回值是"+res); if (res.equals ("abc")){ res="hi"; }else { } } }@Around环绕通知-增强方法有ProceedingJoinPoint参数
package cqutlc.ba03; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import java.util.Date; /* * @Aspect:aspectJ框架中的注解,用来表示当前类是切面类 * 位置:类定义的上面 * */ @Aspect public class MyAspect { /* * 环绕通知定义方法的格式 * 1.public * 2.有一个返回值 object * 3.方法名称自定义 * 4.方法有参数,固定的 ProceedingJoinPoint * * */ /*@Around 特点: 1.功能最强的通知 2.在目标方法前和后都可以加入功能 3.控制目标方法是否被调用实行 4.修改原来的目标方法的执行结果,影响最后的调用结果 环绕通知等同于jdk动态代理,InvocationHandler接口 参数:ProceedingJoinPoint 就等同于Method 作用:执行目标方法的执行结果,可以被修改。 环绕通知:经常做事务,在目标方法之前开启事务,执行目标方法,在目标方法之后提交事务 * */ @Around (value = "execution(* *..SomeServiceImpl.doFirst(..))") public Object myAround(ProceedingJoinPoint pjp) throws Throwable { String name=""; Object[] args =pjp.getArgs (); if (args!=null&&args.length>1){ Object arg= args[0]; name=(String)arg; } //在目标方法前或者后加功能 //实现环绕通知 Object result=null; System.out.println ("环绕通知在目标方法之前"+new Date ()); if ("zhangsan".equals (name)){ //1.实现目标方法的调用 result= pjp.proceed ();//method.invoke,object result=doFirst(); } System.out.println ("环绕通知在目标方法之后,提交事务"); return result; } } package cqutlc.ba03; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class test1 { @Test public void test1(){ String config="applicationContext.xml"; ApplicationContext ac=new ClassPathXmlApplicationContext (config); SomeService proxy=(SomeService)ac.getBean ("someService"); String str=proxy.doFirst ("lc",19); } }@Pointcut定义切入点
当较多的通知增强方法使用相同的execution切入点表达式时,编写、维护均较为麻烦。 AspectJ提供了@Pointcut注解,用于定义execution切入点表达式。其用法是,将@Pointcut注解在一个方法之上,以后所有的execution的value属性值均可使用该方法名作为切入点。代表的就是@Pointcut定义的切入点。这个使用@Pointcut注解的方法一般使用private 的标识方法,即没有实际作用的方法。
属性 :value切入点表达式
位置:自定义的方法的上面
特点:当使用@Pointcut定义在一个方法的上面,此时这个方法的名称就是切入点表达式的别名,其他的通知中,value属性就可以使用这个方法名称代替切入点表达式。
@Pointcut(value="execution(* *..SomeServiceImpl.doOther(..))") private void mypt(){ //无需代码 }有接口也可以使用cglib代理
在xml中配置<aop:aspectj-autoproxy proxy-target-class="true"/>表示告诉框架,你要使用cglib代理。
4.Spring集成MyBatis把mybatis和spring框架集成在一起,像一个框架一样使用。
用的技术是:IOC
为什么ioc能把spring和mybatis集成在一起?是因为ioc能创建对象,可以把mybatis创建的对象交给spring统一创建,开发人员从spring中获取对象。开发人员不用同时面对两个或多个框架了,就面对一个spring就行了。
mybatis使用步骤
我们会使用独立的连接池类替换掉mybatis中自带的连接池,把连接池类也交给spring创建
spring需要创建的对象有:
spring配置文件:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="www.springframework/schema/beans" xmlns:xsi="www.w3/2001/XMLSchema-instance" xsi:schemaLocation="www.springframework/schema/beans www.springframework/schema/beans/spring-beans.xsd"> <!--声明数据源DataSource,作用是连接数据库的--> <bean id="myDataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close"> <!--set注入给DruidDataSource提供连接数据库信--> <property name="url" value="jdbc:mysql://localhost:3306/MySql ?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT"/><!--setUrl注入--> <property name="username" value="root"/> <property name="password" value="131138"/> <property name="maxActive" value="20"/> </bean> <!--声明的是mybatis中提供的SqlSessionFactoryBean类,这个类内部创建SqlSessionFactory--> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <!--set注入,把数据库连接池付给了dataSource--> <property name="dataSource" ref="myDataSource"/> <!--mybatis主配置文件的位置 configLocation属性是Resource类型,读取配置文件 它的赋值,使用的是value,指定路径的文件,使用 classpath:表示文件的位置 --> <property name="configLocation" value="classpath:mybatis.xml"/> </bean> <!--创建dao对象,使用SqlSession的getMapper(studentDao.class) MapperScannerConfigurer:在内部调用getMapper()生产每个dao接口的代理对象。 --> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <!--指定sqlSessionFactory对象的id--> <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/> <!--指定包名,包名是dao接口所在的包名 MapperScannerConfigurer会扫描这个包中的所有接口,把每个接口都执行一次getMapper方法 得到每个接口的dao对象,创建好的dao对象放入到spring容器中 --> <property name="basePackage" value="cqutlc.dao"/> </bean> <!--声明service--> <bean id="studentService" class="cqutlc.service.Impl.StudentServiceImpl"> <property name="studentDao" ref="studentDao"/> </bean> </beans>mybatis配置文件:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE configuration PUBLIC "-//mybatis//DTD Config 3.0//EN" "mybatis/dtd/mybatis-3-config.dtd"> <configuration> <!--日志--> <settings> <setting name="logImpl" value="STDOUT_LOGGING"/> </settings> <!--设置别名--> <typeAliases> <!--name所在包的路径--> <package name="cqutlc.domain"/> </typeAliases> <!--sql mapper映射文件的位置--> <mappers> <!--name是包名--> <package name="cqutlc.dao"/> </mappers> </configuration>测试下:
package cqutlc; import cqutlc.dao.studentDao; import cqutlc.domain.Student; import cqutlc.service.Impl.StudentServiceImpl; import cqutlc.service.StudentService; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import java.util.List; public class test1 { @Test public void test(){ String config="applicationContext.xml"; ApplicationContext ac=new ClassPathXmlApplicationContext (config); //获取spring容器中dao对象 studentDao studentDao=(studentDao) ac.getBean ("studentDao"); Student student=new Student (1005,"lc","444@qq",20); int nums=studentDao.insertStudent (student); //spring和mybatis整合在一起使用,事务是自动提交的,无需执行SqlSessionmit(); System.out.println (nums); } @Test public void test2(){ String config="applicationContext.xml"; ApplicationContext ac=new ClassPathXmlApplicationContext (config); StudentService studentService=(StudentService) ac.getBean ("studentService"); Student student=new Student (1006,"jkl","555@qq",20); int nums=studentService.addStudent (student); System.out.println (nums); } @Test public void test3(){ String config="applicationContext.xml"; ApplicationContext ac=new ClassPathXmlApplicationContext (config); StudentService studentService=(StudentService) ac.getBean ("studentService"); List<Student> students =studentService.queryStudents (); for (Student student : students) { System.out.println (student); } } } 5.Spring事务 5.1spring的事务管理事务原本是数据库中的概念,在Dao层。但是一般情况下,需要将事务提升到业务层,即Service层。这样做是为了能够使用事务的特性来管理具体的业务。
5.2spring事务管理API事务的超时时间:表示一个方法的最长执行时间,如果方法执行时超过时间,就进行事务回滚。
单位:秒,整数,默认-1
事务的传播行为
控制业务方法是否有事务,有的话是什么样的事务。
7个传播行为:表示你的业务方法调用时,事务在方法之间是如何使用的。
PROPAGATION_REQUIRED:指定的方法必须在事务内执行,若当前存在事务,就加入到当前事务中,若当前没有事务,则创建一个新事务。这种传播行为是最常见的选择,也是spring默认的事务传播行为。
PROPAGATION_REQUIRES_NEW:指定的方法支持当前事务,但若当前没有事务,也可以也非事务方式执行。
PROPAGATION_SUPPORTS:总是创建一个新事务,若当前存在事务,就将当前事务挂起,直到新事务执行完毕。
总结spring事务:
1.管理事务的是,事务管理和它的实现类
2.spring的事务是一个统一的模型。
指定要使用的事务管理器实现类,使用 bean
指定哪些类,哪些方法需要加入事务管理功能
指定方法需要的隔离级别和传播行为,超时。
5.3程序举例环境搭建模拟一个销售系统
package cqutlc.service; import cqutlc.dao.GoodsDao; import cqutlc.dao.SaleDao; import cqutlc.domain.Goods; import cqutlc.domain.Sale; import cqutlc.excep.NotEnoughException; public class BuyGoodsServiceImpl implements BuyGoodsService { private SaleDao saleDao; private GoodsDao goodsDao; public void setSaleDao (SaleDao saleDao) { this.saleDao = saleDao; } public void setGoodsDao (GoodsDao goodsDao) { this.goodsDao = goodsDao; } /**/ @Override public void buy (Integer goodsId, Integer nums) { System.out.println ("buy方法的开始"); //记录销售信 Sale sale=new Sale (); sale.setGid (goodsId); sale.setNums (nums); saleDao.insertSale (sale); //更新库存 Goods goods=goodsDao.selectGoods (goodsId); if (goods==null){ throw new NullPointerException ("编号是:"+goodsId+"商品不存在"); }else if(goods.getAmount ()<nums) { //库存不足 throw new NotEnoughException("编号是:"+goodsId+"库存不足!"); } Goods buyGoods=new Goods (); buyGoods.setId (goodsId); buyGoods.setAmount (nums); goodsDao.updateGoods (buyGoods); System.out.println ("buy方法的结束"); } } 5.4使用spring的事务注解管理事务两种处理事务的方法:
1.适合于中小项目使用的:注解方法
spring框架自己用aop实现给业务方法增加事务的功能,使用 @Transactional注解增加事务
使用@Transactional的步骤
1.需要声明事务管理器对象
<bean id="xx" class="DataSourceTransactionManager">
2.开启事务注解驱动,告诉spring框架,我要使用注解的方式管理事务。
spring使用aop机制,创建@Transactional所在的类代理对象,给方法加入事务的功能。
spring给业务方法加入事务:在你的业务方法执行之前,先开启事务,在业务方法执行结束后提交或者回滚事务,使用aop的环绕通知
3.在方法上加入@Transactional
<!--使用spring的事务处理--> <!--声明事务管理器--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <!--连接的数据库,制定数据源--> <property name="dataSource" ref="myDataSource"/> </bean> <!--2.开启事务注解驱动,告诉spring使用注解管理事务,创建代理对象 transactionManager:事物管理器对象id--> <tx:annotation-driven transaction-manager="transactionManager"/> /* * rollbackFor表示发生指定的异常一定回滚 * */ @Transactional( propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, readOnly = false, rollbackFor = { NullPointerException.class,NotEnoughException.class } ) @Override ....省略(同上 5.5使用AspectJ的AOP配置管理事务适合大型项目,有很多的类,方法,需要大量的配置事务,使用aspectJ框架功能,在spring配置文件中声明类,方法需要的事务。这种方式业务方法和事务配置完全分离。
实现步骤:都是在xml配置文件中实现。
1.要使用的是aspectJ框架需要加入对应的依赖。
2.声明事务管理器对象
<bean id="xx" class="DataSourceTransactionManager">
3.声明方法需要的事务类型(配置方法的事物属性【隔离级别,传播行为,超时】)
4.配置aop,哪些类需要创建代理。
6.Spring与Webweb项目中容器对象只需要创建一次,把容器对象放入到全局作用域ServletContext中。
怎么实现:
使用监听器,当全局作用域对象被创建时,创建容器存入ServletContext
监听器作用:
1.创建容器对象,执行ApplicationContext ac=new ClassPathXmlApplicationContext (config);
2.把容器对象放入到ServletContext,ServletContext.setAttribute(key,ac)
监听器可以自己创建也可以用框架写好的 ContextLoaderListener
web.xml文件的配置
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="xmlns.jcp/xml/ns/javaee" xmlns:xsi="www.w3/2001/XMLSchema-instance" xsi:schemaLocation="xmlns.jcp/xml/ns/javaee xmlns.jcp/xml/ns/javaee/web-app_4_0.xsd" version="4.0"> <servlet> <servlet-name>RegisterServlet</servlet-name> <servlet-class>cqutlc.controller.RegisterServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>RegisterServlet</servlet-name> <url-pattern>/registerServlet</url-pattern> </servlet-mapping> <!--注册监听器ContextLoaderListener 监听器被创建对象后,会读取/WEB-INF/spring.xml 可以修改默认的文件位置,使用context-param重新指定文件的位置 配置监听器:目的是创建容器对象,创建了容器对象,就能把spring.xml配置文件中的所有对象都创建好 用户发起请求就可以直接调用对象了。 --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> </web-app>spring配置文件
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="www.springframework/schema/beans" xmlns:xsi="www.w3/2001/XMLSchema-instance" xsi:schemaLocation="www.springframework/schema/beans www.springframework/schema/beans/spring-beans.xsd"> <!--声明数据源DataSource,作用是连接数据库的--> <bean id="myDataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close"> <!--set注入给DruidDataSource提供连接数据库信--> <property name="url" value="jdbc:mysql://localhost:3306/MySql ?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT"/><!--setUrl注入--> <property name="username" value="root"/> <property name="password" value="131138"/> <property name="maxActive" value="20"/> </bean> <!--声明的是mybatis中提供的SqlSessionFactoryBean类,这个类内部创建SqlSessionFactory--> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <!--set注入,把数据库连接池付给了dataSource--> <property name="dataSource" ref="myDataSource"/> <!--mybatis主配置文件的位置 configLocation属性是Resource类型,读取配置文件 它的赋值,使用的是value,指定路径的文件,使用 classpath:表示文件的位置 --> <property name="configLocation" value="classpath:mybatis.xml"/> </bean> <!--创建dao对象,使用SqlSession的getMapper(studentDao.class) MapperScannerConfigurer:在内部调用getMapper()生产每个dao接口的代理对象。 --> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <!--指定sqlSessionFactory对象的id--> <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/> <!--指定包名,包名是dao接口所在的包名 MapperScannerConfigurer会扫描这个包中的所有接口,把每个接口都执行一次getMapper方法 得到每个接口的dao对象,创建好的dao对象放入到spring容器中 --> <property name="basePackage" value="cqutlc.dao"/> </bean> <!--声明service--> <bean id="studentService" class="cqutlc.service.Impl.StudentServiceImpl"> <property name="studentDao" ref="studentDao"/> </bean> </beans>RegisterServlet类
package cqutlc.controller; import cqutlc.domain.Student; import cqutlc.service.StudentService; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.support.WebApplicationContextUtils; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; public class RegisterServlet extends HttpServlet { protected void doPost (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("UTF-8"); String strId=request.getParameter ("id"); String strName=request.getParameter ("name"); String strEmail=request.getParameter ("email"); String strAge=request.getParameter ("age"); //创建spring的容器对象 //String config="spring.xml"; //ApplicationContext ac=new ClassPathXmlApplicationContext (config); /*WebApplicationContext ac=null; //获取servletContext中的容器对象,创建好的容器对象,拿来就用 String key=WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE; Object attr= getServletContext ().getAttribute (key); if (attr!=null){ ac=(WebApplicationContext)attr; }*/ WebApplicationContext ac=null; ServletContext sc=getServletContext (); ac=WebApplicationContextUtils.getRequiredWebApplicationContext (sc); System.out.println ("容器对象的信=="+ac); //获取service StudentService studentService=(StudentService) ac.getBean ("studentService"); Student student=new Student (); student.setId (Integer.parseInt (strId)); student.setName (strName); student.setEmail (strEmail); student.setAge (Integer.parseInt (strAge)); studentService.addStudent (student); //给一个结果页面 request.getRequestDispatcher ("/result.jsp").forward (request,response); } protected void doGet (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { } } protected void doGet (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { }} `` 到这里就结束了,如果有什么疑问,欢迎评论,一起学习,一起进步O(∩_∩)O
版权声明:本文标题:万字Spring框架学习总结(附核心代码详细注释) 内容由林淑君副主任自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.xiehuijuan.com/baike/1687049984a130331.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论