Spring
简介
行业春天
解决企业级开发的复杂性,使现有的技术更容易使用,本身是个大杂烩,整合了现有的技术框架
不要重复造轮子
- SSH:Struct2+Spring+Hibernate
- SSM:SpringMVC+Spring+Mybatis
官网:https://spring.io/projects/spring-framework#overiew
官方下载地址:https://repo.spring.io/release/org/springframework/spring/
可以下载到所有的版本
GitHub:https://github.com/spring-projects/spring-framework
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.7.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.7.RELEASE</version>
</dependency>
两个包:
- springWebMVC
- springJDBC
Spring优点
- Spring是一个开源的免费的框架(容器)
- Spring是一个轻量级,非入侵式框架!
- 不会对原来项目有影响
- 控制反转(IOC),面向切面编程(AOP)
- 支持事务处理,对框架整合的支持
Spring是一个轻量级的控制反转(IOC)和面向切面编程(AOP)的框架
Spring组成
spring组成的七大模块
- 核心容器(SpringCore)
- 核心容器提供Spring框架的基本功能。spring以bean的方式组织和管理Java应用的各个组件及其关系,spring使用BeanFactory来产生和管理Bean,是工厂模式的实现,BeanFactory使用控制反转(IoC)模式将应用的配置和依赖性规范与实际的应用程序代码分开
- 应用上下文(Spring Context)
- Spring上下文是一个配置文件,向spring提供上下文信息,spring上下文包括企业服务、、、、
- Spring面向切面编程(Spring AOP)
- AOP(Aspect Oriented Programming)
- 通过配置管理特性,SpringAOP模块直接将面向方法的编程功能集成在了Spring框架中,Spring管理的任何对象都支持AOP,SpringAOP模块基于Spring的应用程序中的对象提供了事务管理服务,通过使用SpringAOP,不用依赖EJB组件,就可以将声明性事务管理集成在应用程序中
- JDBC和DAO模块(Spring DAO)
- Dao(Data Access Object)
- JDBC、DAO的抽象层,提供了有意义的异常层次结构实现,可用该结构来管理异常处理,和不同数据库提供商抛出的错误信息,异常层次结构简化了错误处理,并且极大的降低了需要编写的代码数量,比如打开和关闭链接。
- 对象实体映射(Spring ORM)
- ORM(Object Relational Mapping)
- Spring插入了若干个ORM框架,提供了ORM对象的关系工具,其中包括Hibernate,JDO和IBatisSQL Map等,所有这些都遵从Spring的通用事务和DAO异常层次结构
- Web模块(Spring Web)
- web上下文模块建立应用程序上下文模块之上,基于web的应用程序提供了上下文,所以spring框架支持与Struts集成,web模块还简化了处理多部分请求以及将请求参数绑定到域对象的工作
- MVC模块(SpringWebMVC)
- MVC(Model View Controller)
- MVC框架是一个全功能的构建Web应用程序的MVC实现,通过策略接口,MVC框架编程高度可配置的,MVC容纳了大量视图技术,其中包括JSP,POI等,模型由JavaBean来构成,存放于m当中,而视图是一个接口,负责实现模型,控制器表示逻辑代码,由c的事情。spring框架的功能可以用在任何J2EE服务器当中,大多数功能也适用于不受管理的环境,spring的核心要点就是支持不绑定到特定J2EE服务的可重用业务和数据的访问对象,毫无疑问这样的对象可以在不同的J2EE环境,独立应用程序和测试环境之间重用
Spring介绍
- SpringBoot
- 快速开发脚手架
- 可以快速开发单个微服务,把一个功能单独提取出来就是一个微服务
- 约定大于配置,主要学习他的配置
- 学习SpringBoot的前提是要掌握Spring和SpringMVC
- SpringCloud
- SpringCloud基于SpringBoot实现的
IOC理论推导
之前使用的流程:
- UserDao接口
- UserDaoImpl实现类
- UserService业务接口
- UserServiceImpl业务实现类
在之前的业务中,用户的需求会影响到我们原来的代码,需要根据用户需求去修改源代码,如果程序代码量巨大,修改一次的成本十分昂贵
使用set接口来实现也是一种动态实现 值的注入
- 之前,程序是主动创建对象,控制权在程序员手上
- 使用了set注入后,程序不再具有主动性,而是变成了被动的接受对象
这种思想,本质上解决了问题,程序员不用再去管理对象的创建,系统的耦合性大大的降低,可以更加专注的在业务的实现上,这是IOC的原型
以前的架构
现在的架构
IOC本质
- 是一种设计思想,DI(依赖注入)是实现IOC的一种方法,原先创建对象由程序自己控制,控制反转后,创建转移给第三方,获得依赖对象的方式反转了
- IoC是Spring框架的核心内容
- 可以使用XML配置
- 可以使用注解
- 不配置也行,自动装填
- 控制反转时一种通过描述(XML或注解)并通过第三方生产或获取特定对象的方式,在Spring中实现控制反转的时IoC容器,其实现方法是依赖注入(Dependency Injection ,DI)
HelloSpring
制作一个简单演示,如何将new对象交给第三方来做,用户可以通过修改xml文件来实现IoC操作
- 导入包
- 配置类加载路径应用上下文xml文件
- 编写JavaBean
- 测试,通过上下文获取bean来new对象
-
导入包
-
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.2.7.RELEASE</version> </dependency>
-
主要是这个,其他随意
-
-
配置类加载路径应用上下文xml文件
-
文件名,spring官方文档是有说的,官方推荐起名为ApplicationContext
-
官方有给初始模板
-
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="..." class="..."> <!-- collaborators and configuration for this bean go here --> </bean> <bean id="..." class="..."> <!-- collaborators and configuration for this bean go here --> </bean> <!-- more bean definitions go here --> </beans>
-
-
编写Bean
-
@Data public class Hello { private String str; }
-
写好bean之后要写入ApplicationContext
-
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="Hello" class="com.haoyun.POJO.Hello"> <property name="str" value="haoyun"/> </bean> </beans>
-
设置一个id,对里面的成员变量可以进行设置
-
设置好的Bean会有一个小标志
-
-
测试
-
public class MyTest { @Test public void BeanTest(){ ApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("Beans.xml"); Hello hello = (Hello) classPathXmlApplicationContext.getBean("Hello"); System.out.println(hello.toString()); } }
-
填应用上下文的位置,产生出了ApplicationContext对象就能获取里面的Bean了,产生Bean对象
-
IOC创建对象的方式
-
使用无参构造创建对象,默认
-
使用有参构造,通过构造器创建
-
@Data public class Hello { private String name; public Hello(String name){ } }
-
添加了一个有参构造函数
-
<bean id="Hello" class="com.haoyun.POJO.Hello"> <property name="name" value="sdafsdf"/> </bean>
-
配置没变
-
爆出错误提示
-
没有找到默认的构造函数
-
这时就要看官方文档了,这里找到一篇中文的官方文档
-
https://www.docs4dev.com/docs/zh/spring-framework/5.1.3.RELEASE/reference/core.html#beans
-
里面讲到一个有参构造器的依赖注入问题
-
依赖注入的两种变体
DI依赖注入存在两种主要变体:Constructor 和Setter 的两种依赖注入
Constructor
-
<beans> <bean id="thingOne" class="x.y.ThingOne"> <constructor-arg ref="thingTwo"/> <constructor-arg ref="thingThree"/> </bean> <bean id="thingTwo" class="x.y.ThingTwo"/> <bean id="thingThree" class="x.y.ThingThree"/> </beans>
-
有参构造函数以这种形式注册,然后包括了下列三种形式
-
<bean id="exampleBean" class="examples.ExampleBean"> <constructor-arg type="int" value="7500000"/> <constructor-arg type="java.lang.String" value="42"/> </bean>
-
如果参数是简单类型就添加type和value,(根据类型的)
-
<bean id="exampleBean" class="examples.ExampleBean"> <constructor-arg index="0" value="7500000"/> <constructor-arg index="1" value="42"/> </bean>
-
还可以使用索引,从0开始(根据索引的)
-
<bean id="exampleBean" class="examples.ExampleBean"> <constructor-arg name="years" value="7500000"/> <constructor-arg name="ultimateAnswer" value="42"/> </bean>
-
消除歧义,加入name,直接规定argument 的name(根据参数名的)
Setter
调用no-argument构造函数,或static工厂方法来实例化Bean
ApplicationContext管理Beans的Constructor和setter的DI,
可以使用properties的格式,但是一般使用XML,或者注解@Controller等
Constructor和Setter是可以混合使用的
Setter注入应该要有合理的默认值,否则,应该添加not-null检查
- 可以由xml、JavaCode、annotations指定
- 每个property(属性)或构造函数参数都要设置value的实际定义,或是容器的另一个引用,如参数不是基本类型,就要找到容器中对应bean的reference(引用)
循环依赖
- classA通过构造函数实注入实现classB,classB又通过构造函数注入实现classA,这种配置bean的相互注入,会被SpringIoC判定为循环reference,并抛出BeanCurrentlyInCreationException
- 要求beanA和beanB之间必须有一个被完全初始化,再注入另一个,典型的先有鸡还是先有蛋的问题
Setter-Based example
-
public class ExampleBean { private AnotherBean beanOne; private YetAnotherBean beanTwo; private int i; public void setBeanOne(AnotherBean beanOne) { this.beanOne = beanOne; } public void setBeanTwo(YetAnotherBean beanTwo) { this.beanTwo = beanTwo; } public void setIntegerProperty(int i) { this.i = i; } }
-
<bean id="exampleBean" class="examples.ExampleBean"> <!-- setter injection using the nested ref element --> <property name="beanOne"> <ref bean="anotherExampleBean"/> </property> <!-- setter injection using the neater ref attribute --> <property name="beanTwo" ref="yetAnotherBean"/> <property name="integerProperty" value="1"/> </bean> <bean id="anotherExampleBean" class="examples.AnotherBean"/> <bean id="yetAnotherBean" class="examples.YetAnotherBean"/>
-
和constructor-based的差距真不大,只是多了一点环节而已
-
<bean id="exampleBean" class="examples.ExampleBean"> <!-- constructor injection using the nested ref element --> <constructor-arg> <ref bean="anotherExampleBean"/> </constructor-arg> <!-- constructor injection using the neater ref attribute --> <constructor-arg ref="yetAnotherBean"/> <constructor-arg type="int" value="1"/> </bean> <bean id="anotherExampleBean" class="examples.AnotherBean"/> <bean id="yetAnotherBean" class="examples.YetAnotherBean"/>
-
wc,东西太多了,根本翻不完,形式太多,表达的又是相近的意思
最简单就直接
<bean id="Hello" class="com.haoyun.POJO.Hello">
<constructor-arg name="name" value="haoyun"/>
</bean>
真是没事找事
别名alias
<bean id="Hello" class="com.haoyun.POJO.Hello">
<constructor-arg name="name" value="haoyun"/>
</bean>
<alias name="Hello" alias="safsdf"/>
原来的名字也能用,别名也能用
这个又是没用的,直接再bean标签使用name也能起别名,里面的内容,用逗号或分号或空格都能起别名
<bean id="Hello" class="com.haoyun.POJO.Hello" name="hello afsdfaf,sadfasdf">
import配置文件
之前官网说一个正规的beans命名为applicationContext.xml,这是一个总的配置文件,项目中可以有多个配置文件,这样的好处是,可以由多个人编写,最后汇总,汇总到主配置文件applicationContext.xml
ApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("applicationContext.xml","Beans.xml");
创建ApplicationContext实例的时候可以选用多个配置文件
或者只选择applicationContext.xml配置文件,将其他的配置文件导入applicationContext.xml
<import resource="Beans.xml"/>
<import resource="Beans1.xml"/>
<import resource="Beans2.xml"/>
多个Beans中配置相同的内容是没关系的
DI依赖注入
几种方式注入,Constructor注入,setter注入,拓展方式注入
Set方式注入
- 依赖注入:set注入
- 依赖:Bean对象的创建依赖于容器
- 注入:Bean对象中的说有属性,由容器来注入
搭建环境
- 复杂类型
- 真实测试对象
直接把官网的举例的所有类型一次做出来
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- <import resource="Beans.xml"/>-->
<!-- <import resource="Beans1.xml"/>-->
<!-- <import resource="Beans2.xml"/>-->
<bean id="address" class="com.haoyun.POJO.Address"/>
<bean id="student" class="com.haoyun.POJO.Student">
<!--普通值注入,value-->
<property name="name" value="asdfafd"/>
<!--Bean注入,ref-->
<property name="address" ref="address"/>
<!--数组注入-->
<property name="books">
<array>
<value>asdfsdf</value>
<value>asdfasd</value>
<value>sdfasdfa</value>
<value>asdfasdfqwer</value>
</array>
</property>
<!--list-->
<property name="hobbys">
<list>
<value>adf</value>
<value>wer</value>
<value>trey</value>
</list>
</property>
<!--map-->
<property name="card">
<map>
<entry key="asdf" value="asdfsf"/>
<entry key="asdfsdf" value="asdfsf"/>
<entry key="asddsaff" value="asdfsf"/>
</map>
</property>
<!--set-->
<property name="games">
<set>
<value>sadf</value>
<value>ssadf</value>
<value>sdadf</value>
</set>
</property>
<!--null-->
<property name="wife">
<null/>
</property>
<!--properties-->
<property name="info">
<props>
<prop key="sadf">werqwer</prop>
<prop key="sasdf">werqwer</prop>
<prop key="saddf">werqwer</prop>
</props>
</property>
</bean>
</beans>
- value
- ref
- list、map、set、properties
- null
- 其他类型
p-namespace、c-namespace
命名空间,这两个能进行的操作其他的操作也能实现,还不一定简便了,要先添加配置支持扩展使用命名空间
xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
添加在applicationContext.xml上,才可以使用,p和c标签
p表示property,用于有无参构造函数的bean对象的依赖注入操作
c表示Constructor,用于有 有参构造函数的bean对象的依赖注入操作
<!--c:constructor 需要有参构造器-->
<bean id="User" class="com.haoyun.POJO.User" c:age="12" c:name="asdfsf"/>
<!--p:property 需要无参构造器-->
<bean id="User2" class="com.haoyun.POJO.User" p:age="13" p:name="sdf"/>
测试
@Test
public void BeanTest(){
ApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
//Student student = (Student) classPathXmlApplicationContext.getBean("student");
User user = (User) classPathXmlApplicationContext.getBean("User");
User user2 = (User) classPathXmlApplicationContext.getBean("User2");
System.out.println(user.toString());
System.out.println(user2.toString());
}
Bean-Scopes作用域
- Singleton 单例
- Prototype 原型
- request 请求
- session 会话
- application 应用
- WebSocket 连接
主要使用前两种
Singleton 单例模式
单例模式是Spring的默认机制
只管理Singleton bean 的一个共享实例,带有一个或多个match bean定义的id到导致只返回一个特定的bean实例
定义的bean限定为singleton时,只创建该bean定义的object的一个实例,存储在singleton缓存中,后续的请求都引用缓存中的实例
只创建一个实例
这个共享实例被共享到每个协作对象中
Spring中的singleton bean概念于singleton pettern的概念不同,如果在单个 Spring 容器中为特定 class 定义一个 bean,则 Spring 容器将创建该_ bean 定义所定义的 class 的一个且仅一个实例。
<bean id="accountService" class="com.something.DefaultAccountService"/>
<!-- the following is equivalent, though redundant (singleton scope is the default) -->
<bean id="accountService" class="com.something.DefaultAccountService" scope="singleton"/>
Demo
-
<bean id="studentTest" class="com.haoyun.POJO.Student" > <property name="address" ref="address"/> </bean> <bean id="studentTest2" class="com.haoyun.POJO.Student" > <property name="address" ref="address"/> </bean> <bean id="address" class="com.haoyun.POJO.Address" p:address="address" scope="singleton" />
-
address是单例模式的,根据单例模式的性质,应该值会创建一个实例,那只创建一个实例,那些被创建的实例中的address成员使用的应该是同一个引用
-
@Test public void BeanTest(){ ApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); Student studentTest = (Student) classPathXmlApplicationContext.getBean("studentTest"); Student studentTest2 = (Student) classPathXmlApplicationContext.getBean("studentTest2"); System.out.println(studentTest); System.out.println(studentTest2); System.out.println(studentTest == studentTest2); System.out.println(studentTest.getAddress() == studentTest2.getAddress()); }
-
得出的结果是两个对象是不同的,但是address是同一个对象,使用同一个reference
ProtoType 原型模式
bean部署的不是单例模式的原型范围都会创建一个新的bean实例,并对该特定bean发出请求,
每个bean都是一个单独的对象
配置和组装object交给client,client code必须清理prototype-scoped object释放原型beans所拥有的昂贵资源,之后可以尝试自定义bean post-processor,释放资源
<bean id="accountService" class="com.something.DefaultAccountService" scope="prototype"/>
每次从容器中get的时候都会产生一个新的对象
其余的request,session,application,这些只能在web开发中使用到,自行理解
Bean的自动装配
- 自动装配,spring满足bean依赖的一种方式
- autowire
- spring会在上下文中自动寻找,并自动给bean装配属性
在spring中有三种装配方式
- 在xml中显示的配置
- 在java中显示的配置
- 隐式 的自动装配bean【重要】
XML Configuration Demo
-
原先使用的方法
-
<bean id="cat" class="com.haoyun.POJO.Cat"/> <bean id="dog" class="com.haoyun.POJO.Dog"/> <bean id="People" class="com.haoyun.POJO.People"> <property name="name" value="haoyun"/> <property name="cat" ref="cat"/> <property name="dog" ref="dog"/> </bean>
-
@Test public void CatDogTest(){ ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); People people = (People) classPathXmlApplicationContext.getBean("People"); people.getCat().shout(); people.getDog().shout(); classPathXmlApplicationContext.registerShutdownHook(); }
-
其他类需要使用ref
-
现在加入两个自动装配的autowire选项
-
byName
-
<bean id="cat" class="com.haoyun.POJO.Cat"/> <bean id="dog" class="com.haoyun.POJO.Dog"/> <!-- <bean id="dog1" class="com.haoyun.POJO.Dog"/>如果这里的id更改,就找不到了--> <!--byName:会自动再容器上下文查找,和自己对象set方法后面值对应的bean id--> <bean id="People" class="com.haoyun.POJO.People" autowire="byName"> <property name="name" value="haoyun"/> </bean>
-
-
byType
-
<bean id="cat" class="com.haoyun.POJO.Cat"/> <bean class="com.haoyun.POJO.Dog"/> <!-- <bean id="dog" class="com.haoyun.POJO.Dog"/> 但是不能配重,全局只能有一个--> <!--连bean-id都可以不用--> <!--byType:自动在容器的上下文查找,和自己对象相同类型bean--> <bean id="People" class="com.haoyun.POJO.People" autowire="byType"> <property name="name" value="haoyun"/> </bean>
Annotation-based Container Configuration
使用annotation配置更加简洁,Spring都支持这两种配置风格
spring2.0引用了@Required
spring2.5采用通用的方法来驱动spring依赖注入@Autowired
2.5还添加了JSR-250注释的支持,@PostConstruct和@PreDestroy
(初始化方法)(销毁方法)
需要注册单独的Bean定义,和context命名空间
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
">
<context:annotation-config/>
</beans>
主要是添加这三句话
@Autowired
-
可以放在构造函数上
-
public class MovieRecommender { private final CustomerPreferenceDao customerPreferenceDao; @Autowired public MovieRecommender(CustomerPreferenceDao customerPreferenceDao) { this.customerPreferenceDao = customerPreferenceDao; } // ... }
-
如果目标bean仅定义在一个开头的构造函数,则不需要在这样的构造函数上使用@Autowired,但是如果有几个构造器可用,则必须注释至少一个构造器,告诉容器使用哪一个
-
还可以放在setter方法上
-
public class SimpleMovieLister { private MovieFinder movieFinder; @Autowired public void setMovieFinder(MovieFinder movieFinder) { this.movieFinder = movieFinder; } // ... }
-
可以放在方法上
-
public class MovieRecommender { private MovieCatalog movieCatalog; private CustomerPreferenceDao customerPreferenceDao; @Autowired public void (MovieCatalog movieCatalog, CustomerPreferenceDao customerPreferenceDao) { this.movieCatalog = movieCatalog; this.customerPreferenceDao = customerPreferenceDao; } // ... }
-
可以应用于字段,甚至可以与构造函数混合使用
-
public class MovieRecommender { private final CustomerPreferenceDao customerPreferenceDao; @Autowired private MovieCatalog movieCatalog; @Autowired public MovieRecommender(CustomerPreferenceDao customerPreferenceDao) { this.customerPreferenceDao = customerPreferenceDao; } // ... }
-
这里使用的@Autowired注解的(member,set,constructor,method)都需要在xml中注入声明,否则在运行时找不到相匹配的(match)
-
<context:annotation-config/> <bean id="cat" class="com.haoyun.POJO.Cat"/> <bean id="dog" class="com.haoyun.POJO.Dog"/> <bean id="People" class="com.haoyun.POJO.People" p:name="asdfadf"/>
-
需要注入声明
-
还可以对array类型的字段和方法使用@Autowired
-
public class MovieRecommender { @Autowired private MovieCatalog[] movieCatalogs; // ... }
-
set集合
-
public class MovieRecommender { private Set<MovieCatalog> movieCatalogs; @Autowired public void setMovieCatalogs(Set<MovieCatalog> movieCatalogs) { this.movieCatalogs = movieCatalogs; } // ... }
-
Map
-
public class MovieRecommender { private Map<String, MovieCatalog> movieCatalogs; @Autowired public void setMovieCatalogs(Map<String, MovieCatalog> movieCatalogs) { this.movieCatalogs = movieCatalogs; } // ... }
-
required=false,这个对象可以为nul
-
public class SimpleMovieLister { private MovieFinder movieFinder; @Autowired(required = false) public void setMovieFinder(MovieFinder movieFinder) { this.movieFinder = movieFinder; } // ... }
-
这个构造函数不传参也可以
-
使用@Nullable也可以表示可以为null
-
public class SimpleMovieLister { @Autowired public void setMovieFinder(@Nullable MovieFinder movieFinder) { ... } }
-
使用限定自动装配
-
@Qualifier("")
-
public class MovieRecommender { @Autowired @Qualifier("main") private MovieCatalog movieCatalog; // ... }
-
算了太长
-
完全看不完
-
说下视频中讲解的主要内容吧
-
@Autowired如何实现
-
先以ByType方式实现
-
在context中寻找使用@Autowired注解使用的同类型的注解声明,
-
<bean class="com.haoyun.POJO.Cat"/> <bean class="com.haoyun.POJO.Dog"/> <bean id="People" class="com.haoyun.POJO.People" p:name="asdfadf"/>
-
没有bean-id都没关系,先是根据type寻找
-
<bean id="cat1" class="com.haoyun.POJO.Cat"/> <bean id="cat2" class="com.haoyun.POJO.Cat"/> <bean id="dog1" class="com.haoyun.POJO.Dog"/> <bean id="dog2" class="com.haoyun.POJO.Dog"/> <bean id="People" class="com.haoyun.POJO.People" p:name="asdfadf"/>
-
但是出现这种类型相同,就不知道怎么选了,就会报错,需要加入一个bean-id限定@Qualifier("")
-
就会引用到bean-id为dog1上的注入声明
-
-
@Resouce注解也有同样的用处,不过用的比较多的是@Autowired
-
Resouce是先查找byName的,不行再查找byType
-
Autowired先查找byType,再查找byName
-
@Resource注解中有很多可使用的参数
-
name和type的意思应该很明了
-
NoUnique不唯一
-
@Resource(type = Dog.class) @Resource(name = "cat1")
-
总结一下:
-
@Autowired先以bytype方式查找,之后以byName方式查找
- 可以定义在很多处位置,但是直接定义在成员上最方便
- 可以配合@Qualifier注解进行限定
- 内置required参数可以允许参数为null和@Nullable功能一致
- 这个注解是spring的
-
@Resource以byName方式查找,之后以byType方式查找
- 内置很多参数,使用方便
- 这个注解是java的,在spring还是多用spring的注解吧
-
使用注解开发
在Spring4之后,要使用注解开发,必须要保证AOP的包导入了
-
bean
-
属性如何注入
-
在applicationContext.xml中指定要扫描的包,才能使用注解
-
<!--指定要扫描的包,这个包小的注解就会生效--> <context:component-scan base-package="com.haoyun.POJO"/>
-
-
衍生的注解
-
@Component有几个衍生注解,我们在web开发中,会按照MVC三层架构分层
- 添加后应该看得到叶子
-
dao【@Repository】
-
@Repository public class User { @Value("haoyun") private String name ; }
-
-
service【@Service】
-
@Service
-
-
controller【@Controller】
-
@Controller
-
四个注解功能是一样的,都是代表将某个类注册到Spring中,装配Bean
-
-
自动装配
- 之前说过
-
作用域
-
@Scope()
-
@Scope("singleton")
-
标记什么模式
-
-
小结
- XML与注解
- XML适用于任何场合,维护简单
- 注解:不是自己的类使用不了,维护相对复杂,
- 最佳配合方法
- xml管理Bean
- 注解只负责完成属性注入
- 还是觉得xml好用,配合lambox好用
使用Java的方式配置Spring
完全不使用XML配置文件,全部使用Java的方式来做
-
@Configuration @ComponentScan("com.haoyun.POJO") public class HaoyunConfig { @Bean public User UserBean() { return new User(); } }
-
经过@Configuration的配置HaoyunConfig已经成为一个配置类了,类似于Context.xml配置文件
-
@ComponentScan设置查找范围
-
@Bean相当于之前写的Bean标签,id就是方法名
-
方法的返回值相当于class
-
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Component public @interface Configuration { @AliasFor( annotation = Component.class ) String value() default ""; boolean proxyBeanMethods() default true; }
-
Configuration的源码中包含了@Component,说明Configuraiton也是一个Component
-
测试
-
@Test public void UserTest() { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(HaoyunConfig.class); //"com.haoyun.controller" /*要与HaoyunConfig中@Bean的method方法名对应*/ User user = (User) context.getBean("UserBean"); System.out.println(user.getName()); }
-
进入ApplicationContext就可以看到里面有很多实现类实现了这个接口
-
ApplicationContext的实现类有很多,ClassPathXmlApplictionContext已经学习过,从xml文件中加载应用上下文
-
现在要通过注解配置应用上下文,所以使用AnnotationConfigApplicationContext
-
AnnotationConfigApplicationContext构造函数有几种
-
传递class的string的,还有一个bean工厂的
-
选用class或配置类的路径
-
如果有多个@Configuration,可以使用@Import注解,加入配置类
-
@Configuration @ComponentScan("com.haoyun.POJO") @Import(config2.class) public class HaoyunConfig { @Bean public User UserBean() { return new User(); } }
JavaConfig是spring的一个子项目,是spring4之后的核心功能
代理模式
SpringAOP的底层,SpringAOP和SpringMVC必问
代理模式:
- 静态代理
- 动态代理
静态代理
- 抽象角色:一般会使用接口或者抽象类来解决
- 真实角色:被代理的角色
- 代理角色:代理真实角色,代理真实角色后,我们一般会做一些附属操作
- 客户:访问代理对象的人
租房例子
客户找中介,中介找房东,实现租房的方法,还能添加一些附属操作
代码步骤:
- 接口
- 真实角色
- 代理角色
- 客户端访问角色
代理模式的好处:
- 可以使真实角色的操作更加存粹,不用去关注一些公共的业务
- 公共业务交给代理角色,实现业务分工
- 公共业务发生扩展时,方便管理
缺点:
- 一个真实角色就会产生一个代理角色,代码量增多
如果一条线已经做出来了,突然要在中间加一个功能,不能去修改原有的业务代码,在公司中是大忌,只能在原有的基础上添加功能,通过代理,调用的是原有的功能,但是在调用原有的功能的同时能像上面的租房的例子一样,增加一些功能,要去学习下面向对象七大特性
动态代理
静态代理每代理一个被代理角色就要重新编写一个静态代理对象,代码量也十分庞大
动态代理的代理类是动态生成的,不是直接写好的
动态代理分两大类:
- 基于接口的动态代理
- JDK原生的动态代理【这里使用】
- 基于类的动态代理
- 基于类的cglib
- 但是现在用的比较多的是基于java字节码来实现的JavaAssist
需要了解两个类:Proxy,InvocationHandle
- Proxy代理
- InvocationHandle调用处理程序
通过反射的方式,判断被代理对象的类型,处理代理实例
public class ProxyInvocationHandler implements InvocationHandler {
private Object target;
public void setTarget(Object target) {
this.target = target;
}
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(),
target.getClass().getInterfaces(),this);
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = method.invoke(target,args);
return result;
}
}
这个代理对象能添加功能,也能执行被代理对象的方法
AOP
不改变原有的业务,增加功能
AOP在Spring中的作用
- 横切关注点:跨越应用程序多个模块的方法或功能,于我们业务逻辑无关,但需要关注的部分
- 切面(aspect):横切关注点被模块化的特殊对象,是一个类
- 通知(Adivce):切面必须要完成的工作,类中的一个方法
- 目标(Target):被通知的对象
- 代理(Proxy):向目标对象应用通知后创建的对象
- 切入点(PointCut):切面通知 执行的“地点”的定义
- 连接点(JointPoint):于切入点匹配的执行点
SpringAOP中,通过Advice定义横切逻辑,支持五种类型的的advice
AOP不改变原有代码的情况下,去增加新的功能
使用Spring实现AOP
使用Spring的API接口
-
导入包
-
<dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.5</version> </dependency>
-
-
添加applicationContext.xml配置支持
-
xmlns:aop="http://www.springframework.org/schema/aop" http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd
-
-
找到对应的接口和实现类,实现类就是被代理对象
-
public interface UserService { public void add(); public void delete(); public void update(); public void select(); }
-
public class UserServiceImpl implements UserService{ public void add() { System.out.println("add"); } public void delete() { System.out.println("delete"); } public void update() { System.out.println("update"); } public void select() { System.out.println("select"); } }
-
现在制作一个动态代理的横切关注点,需要加在原有的业务前,原有业务执行前,执行这个切片
-
-
制作切片
-
public class Log implements MethodBeforeAdvice { ///** // * @param method:要执行目标对象的方法 // * @param args:参数 // * @param target:目标对象 // * @throws Throwable // */ public void before(Method method, Object[] args, Object target) throws Throwable { System.out.println(target.getClass().getName()+"的"+method.getName()+"被执行"); } }
-
before中是切片执行的方法,通知方式是before,前置通知
-
-
把这个横切关注点加入beans,和
-
<bean id="log" class="com.haoyun.log.Log"/> <bean id="UserServiceImpl" class="com.haoyun.service.UserServiceImpl"/>
-
-
applicationContext.xml配置AOP切入点,切片环绕
-
<aop:config> <!--切入点:expression:表达式(要执行的位置,UserServiceImpl.要切入的方法)--> <aop:pointcut id="pointcut" expression="execution(* com.haoyun.service.UserServiceImpl.*(..))"/> <!--执行环绕增加--> <!--把log切片,切入到pointcut切入点上--> <aop:advisor advice-ref="log" pointcut-ref="pointcut"/> </aop:config>
-
-
测试
-
@Test public void ProxyTest() { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); /*代理的是一个接口*/ UserService userserviceImpl = (UserService) context.getBean("UserServiceImpl",UserService.class); userserviceImpl.add(); }
-
执行add前会先执行log切面
-
使用自定义类
-
public class aspectDiy { public void beforeDiy(){ System.out.println("beforeDiy"); } public void afterDiy(){ System.out.println("afterDiy"); } }
-
<aop:config> <aop:aspect ref="aspectDip"> <!--切入点--> <aop:pointcut id="pointcut" expression="execution(* com.haoyun.service.UserServiceImpl.*(..))"/> <!--通知,切入到哪个点上--> <aop:before method="beforeDiy" pointcut-ref="pointcut"/> <aop:after method="afterDiy" pointcut-ref="pointcut"/> </aop:aspect> </aop:config>
-
选择对应的方法切入就行
-
beforeDiy add afterDiy
使用注解实现
-
先开启注解支持
-
<aop:aspectj-autoproxy/> <context:component-scan base-package="com.haoyun.pointCut"/>
-
@Aspect @Component public class AnnotationPointCut { @Before("execution(* com.haoyun.service.UserServiceImpl.*(..))") public void before(){ System.out.println(AnnotationPointCut.class.getName()+" before"); } @After("execution(* com.haoyun.service.UserServiceImpl.*(..))") public void after(){ System.out.println(AnnotationPointCut.class.getName()+" after"); } }
-
和之前一样测试就行
规范点的化使用第一种方法吧,切面小的话使用第二种方法,第三种方法也不是很简便,要设置切入点还挺麻烦,第一和第二种方法的切入点都可以复用,第三种方法切入点不好复用,差点意思
整合Mybatis
回顾Mybatis
步骤:
-
导入相关包
- junit
- mybatis
- myssql
- spring
- aop
- mybatis-spring
-
编写配置文件
-
测试
-
导包
-
<dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.11</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>5.2.7.RELEASE</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.12</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.2.7.RELEASE</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.2</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.2.7.RELEASE</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.5</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>2.0.5</version> </dependency> </dependencies> <build> <resources> <resource> <directory>src/main/resources</directory> <includes> <include>**/*.properties</include> <include>**/*.xml</include> </includes> <filtering>true</filtering> </resource> <resource> <directory>src/main/java</directory> <includes> <include>**/*.properties</include> <include>**/*.xml</include> </includes> <filtering>true</filtering> </resource> </resources> </build>
-
标准几个东西,顺便导入spring整合要用的一些包
-
mybatis-config.xml
-
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <typeAliases> <package name="com.haoyun.POJO"/> </typeAliases> <environments default="development"> <environment id="development"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="com.mysql.cj.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=false&useUnicode=true&characterEncoding=UTF-8"/> <property name="username" value="root"/> <property name="password" value="123456"/> </dataSource> </environment> </environments> <mappers> <package name="com.haoyun.mapper"/> </mappers> </configuration>
-
User
-
@Data @AllArgsConstructor @NoArgsConstructor public class User { private int id; private String name; private String pwd; }
-
UserMapper
-
public interface UserMapper { List<User> selectUser(); }
-
UserMapper.xml
-
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.haoyun.mapper.UserMapper"> <select id="selectUser" resultType="user"> select * from user </select> </mapper>
-
Test
-
@Test public void UserMapper(){ String resource ="mybatis-config.xml"; InputStream inputStream = null ; try { inputStream = Resources.getResourceAsStream(resource); } catch (IOException e) { e.printStackTrace(); } SqlSessionFactory build = new SqlSessionFactoryBuilder().build(inputStream); SqlSession sqlSession = build.openSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); List<User> users = mapper.selectUser(); for (User user : users) { System.out.println(user); } sqlSession.close(); }
mybatis-spring官方文档
http://mybatis.org/spring/zh/index.html
这里面涉及到mybatis-spring包的版本问题,如果spring版本和mybatis是5.0和3.5版本以上的,要使用Mybatis-spring2.0以上的包
最好就通过阅读mybatis-spring文档来学习
http://mybatis.org/spring/zh/getting-started.html
整合Mybatis方式一
spring的IoC特性,原先的Mybatis中的new对象方法都将制作为bean,进行依赖注入
-
整体结构
-
mybatis-spring的配置将一点点代替原有的mybatis-config.xml中的配置
-
spring-dao.xml可以专门存放dao层的设置
- mybatis都有这几个操作
- 使用SqlSessionFactoryBean读取连接数据库配置文件
- 产生sqlSessionFactory
- 再产生sqlSession
- 然后getMapper执行操作
-
都可以一一代替
-
配置数据源dateSource
-
<!--DateSource:使用spring的数据源替换mybatis的设置:c3p0、dbcp、druid--> <bean id="dateSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=false&useUnicode=true&characterEncoding=UTF-8"/> <property name="username" value="root"/> <property name="password" value="123456"/> </bean>
-
mybatis中的配置数据源操作
-
-
给sqlSessionFactory注入dateSource
-
<!--sqlSessionFactory--> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <!--配置数据源--> <property name="dataSource" ref="dateSource" /> <!--mybatis的核心配置文件,但是可以不写--> <property name="configLocation" value="classpath:mybatis-config.xml"/> <!--相当于mappe package 添加mybatis.xml配置文件--> <property name="mapperLocations" value="classpath:com/haoyun/mapper/UserMapper.xml"/> <!--mybatis配置文件中能配置的在这都能配置--> </bean>
-
-
然后是注入sqlSession
-
<!--SqlSessionTemplate:就是SqlSession--> <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate"> <!--只能使用构造器注入sqlSessionFactory,因为SqlSessionTemplate没有set方法--> <constructor-arg index="0" ref="sqlSessionFactory"/> </bean>
-
这里的注入方法是官网给出的,因为进入SqlSessionTemplate的源码查看,是没有set方法的所以只能通过构造函数注入
-
-
mybatis-config中原有的操作,在spring中都能设置,不过还是建议留一点在mybatis-config.xml中,证明有mybatis-config.xml这个文件
-
原有的mybatis-config.xml就变成这样了
-
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <typeAliases> <package name="com.haoyun.POJO"/> </typeAliases> <!-- <settings>--> <!-- <setting name="" value=""/>--> <!-- </settings>--> <!--一般会留下几个设置,证明使用了mybatis--> <!-- <environments default="development">--> <!-- <environment id="development">--> <!-- <transactionManager type="JDBC"/>--> <!-- <dataSource type="POOLED">--> <!-- <property name="driver" value="com.mysql.cj.jdbc.Driver"/>--> <!-- <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=false&useUnicode=true&characterEncoding=UTF-8"/>--> <!-- <property name="username" value="root"/>--> <!-- <property name="password" value="123456"/>--> <!-- </dataSource>--> <!-- </environment>--> <!-- </environments>--> <!-- <mappers>--> <!-- <package name="com.haoyun.mapper"/>--> <!-- </mappers>--> </configuration>
-
-
配置好spring-dao.xml,要多写一个实现UserMapper接口的实现类,用于注入
-
之前是通过getMapper,然后找到对应的mapper,才能产生对应的对象
-
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
-
现在要通过注入bean来产生对象,这个对象需要注入一个sqlSession才行,sqlsession就是sqlSessionTemplate,再实现类添加一个set方法注入sqlSessionTemplate,sqlSessionTemplate已将在上面注入好,id为sqlSession
-
添加这个实体类的作用就是能注入sqlSession
-
public class UserMapperImpl implements UserMapper { private SqlSessionTemplate sqlSession; public void setSqlSession(SqlSessionTemplate sqlSession) { this.sqlSession = sqlSession; } public List<User> selectUser() { UserMapper mapper = sqlSession.getMapper(UserMapper.class); return mapper.selectUser(); } }
-
代理调用的是mapper.selectUser,这里又映射到UserMapper.xml的selectUser
-
<mapper namespace="com.haoyun.mapper.UserMapper"> <select id="selectUser" resultType="user"> select * from user </select> </mapper>
-
有了实体类就要给他注入bean
-
在applicationContext.xml中注册,因为spring-dao中编写的配置基本已经定形,不必更改了
-
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd"> <import resource="spring-dao.xml"/> <bean id="userMapper" class="com.haoyun.mapper.UserMapperImpl"> <property name="sqlSession" ref="sqlSession"/> </bean> </beans>a
-
import spring-dao.xml配置
-
给userMapper,注入sqlSession,使用的reference引用已经写好的sqlSession bean
-
测试
-
@Test public void UserMapper(){ ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); UserMapper userMapper = context.getBean("userMapper", UserMapper.class); List<User> users = userMapper.selectUser(); for (User user : users) { System.out.println(user); } }
-
读取applicationContext配置文件后,直接getBean,就拿到了实体类对象,就可以调用里面的方法
-
-
这个整合,也就是以springIoC的特性把、读取数据源、产生SqlSessionFactory,产生sqlSession的操作都进行了依赖注入化,通过第三方获取特定的对象,实现解耦
-
整合Mybatis方式二
-
官方文档提供了一个抽象支持类,能提供一个sqlsession,调用getSqlSession就能得到一个SqlSessionTemplate,需要注入一个SqlSessionFactory或SqlSessionTemplate
-
注入SqlSessionFactory,就不用产生SqlSessionTemplate,这样在制作spring-dao.xml配置文件时能少注入一个SqlSessionTemplate
-
<!--SqlSessionTemplate:就是SqlSession--> <!-- <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">--> <!-- <!–只能使用构造器注入sqlSessionFactory,因为SqlSessionTemplate没有set方法–>--> <!-- <constructor-arg index="0" ref="sqlSessionFactory"/>--> <!-- </bean>-->
-
开始注入
-
UserMapperImpl2
-
public class UserMapperImpl2 extends SqlSessionDaoSupport implements UserMapper{ /*省去了注入的过程*/ public List<User> selectUser() { return getSqlSession().getMapper(UserMapper.class).selectUser(); } }
-
spring-dao.xml
-
<bean id="UserMapperImpl2" class="com.haoyun.mapper.UserMapperImpl2"> <property name="sqlSessionFactory" ref="sqlSessionFactory"/> </bean>
-
注入sqlSessionFactory
-
测试方法和之前一样
声明式事务
回顾事务transaction
- 事务在项目开发中十分重要,涉及到数据的一致性
- 事务ACID原则
- 原子性
- 一致性
- 隔离性
- 多个业务可能操作同一个资源,防止数据损坏
- 持久性
- 事务一旦提交,无论系统发生什么问题,结果都不会被影响
这里举了一个例子,进行insert操作和delete操作,insert操作成功,delete操作失败,根据ACID原则,这一组业务应该一起成功或者一起失败
在官方文档中介绍了两种事务的实现类型
http://mybatis.org/spring/zh/transactions.html#configuration
- 交由容器管理事务
- 编程式事务管理
- 根据AOP的特性,最好以横切关注点的方式将切片切入,而不是修改已经写好的业务代码,所以编程式事务管理了解下就行,少用
交由容器管理事务
-
创建一个
DataSourceTransactionManager
对象的,传入DateSource-
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <constructor-arg ref="dataSource" /> </bean>
-
-
添加spring的事务命名空间
-
<tx:jta-transaction-manager />
-
-
找一个容器配置事务,平常不这么丢进去
-
<property name="transactionFactory"> <bean class="org.apache.ibatis.transaction.managed.ManagedTransactionFactory" /> </property>
-
但是举例是结合AOP进行的事务管理
-
添加事务的命名空间
-
可以手打,会自动添加依赖支持
-
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
-
<tx:jta-transaction-manager/>
-
检查下支持是否进来了
-
然后给入数据源创建DataSourceTransactionManager对象,这句是写死的
-
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <constructor-arg ref="dateSource" /> </bean>
-
<!--结合AOP实现事务织入--> <!--配置事务的传播特性,这个属性在晚上搜,事务的传播特性--> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="add" propagation="REQUIRED"/><!--这个属性默认的--> <tx:method name="delete" propagation="REQUIRED"/> <tx:method name="update" propagation="REQUIRED"/> <tx:method name="query" read-only="true"/><!--只读--> <tx:method name="*" propagation="REQUIRED"/> </tx:attributes> </tx:advice> <aop:config> <aop:pointcut id="txPointCut" expression="execution(* com.haoyun.mapper.*.*(..))"/> <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/> </aop:config>
-
<select id="selectUser" resultType="user"> select * from user </select> <insert id="insertUser" parameterType="user"> insert into mybatis.user (id,name,pwd) values (#{id},#{name},#{pwd}) </insert> <delete id="deleteUser" parameterType="int"> deletes from user where id = #{id} </delete>
-
这里的delete是故意写错的,测试会不会insert会不会回滚
-
public interface UserMapper { List<User> selectUser(); int insertUser( User user); int deleteUser( int id); }
-
public class UserMapperImpl2 extends SqlSessionDaoSupport implements UserMapper{ /*省去了注入的过程*/ public List<User> selectUser() { User user = new User(); user.setId(14); user.setName("haoyun"); user.setPwd("123"); UserMapper mapper = getSqlSession().getMapper(UserMapper.class); mapper.insertUser(user); mapper.deleteUser(5); return getSqlSession().getMapper(UserMapper.class).selectUser(); } public int insertUser(User user) { return getSqlSession().getMapper(UserMapper.class).insertUser(user); } public int deleteUser(int id) { return getSqlSession().getMapper(UserMapper.class).deleteUser(id); } }
-
selectUser中放了insert和delete操作,delete操作失败后,会回滚,不会插入进去