1.Spring 5
简介
Spring框架是由于软件开发的复杂性而创建的。Spring使用的是基本的JavaBean来完成以前只可能由EJB完成的事情。然而,Spring的用途不仅仅限于服务器端的开发。从简单性、可测试性和松耦合性角度而言,绝大部分Java应用都可以从Spring中受益。
2002 interface21
地址:https://spring.io/projects/spring-framework#learn
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.6</version>
</dependency>
优点
- 免费的容器
- 是一个轻量级的、非入侵式的框架
- 控制反转(IOC) 面向切面编程(AOP) ***
- 支持事务
拓展
- Spring Boot
- 一个快速开发的脚手架
- 基于SpringBoot可以快速的开发单个微服务
- Spring Cloud
- Spring Cloud是基于SpringBoot实现的
缺点:
发展太过于繁琐,然后违背了理念,配置过于繁琐
2.IOC
我们在设计Dao和Impl时 如果需求要发生改变 则会付出昂贵的代价
所以我们尝试在service层进行一个修改即 我们进行set方法来进行注入dao
public class UserServiceImpl implements UserService{
UserDao userDao=new UserDaoImpl();
@Override
public void setUserDao(UserDao userDao) {
this.userDao=userDao;
}
@Override
public void getUser() {
userDao.getUser();
}
}
@Test
public void UserTest(){
//用户实际上使用的业务层
UserService userService = new UserServiceImpl();
userService.setUserDao(new UserDaoMySqlImpl());
userService.getUser();
}
这种思想从本质上解决了问题,不需要管理对象的创建,只需要专注在业务的实现上。
IOC本质
控制反转IoC(Inversion of Control),是一种设计思想,DI(依赖注入)是实现IoC的一种方法,也有人认为DI只是IoC的另一种说法。没有IoC的程序中 , 我们使用面向对象编程 , 对象的创建与对象间的依赖关系完全硬编码在程序中,对象的创建由程序自己控制,控制反转后将对象的创建转移给第三方,个人认为所谓控制反转就是:获得依赖对象的方式反转了。
控制反转是一种通过描述(XML或注解)并通过第三方去生产或获取特定对象的方式。在Spring中实现控制反转的是IoC容器,其实现方法是依赖注入(Dependency Injection,DI)。
3.HelloSpring
<!-- 这里开始使用Spring
bean 相当于对象 相当于new Hello
bean = > Hello hello = new Hello
id 相当于变量名
class 相对于new 的对象
property 相当于变量
-->
<bean id="hello" class="com.xue.pojo.Hello">
<property name="str" value="Spring"/>
</bean>
test实
@Test
public void myTest() {
//使用xml来加载 获取上下文的对象
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
Hello hello = (Hello) context.getBean("hello");
System.out.println(hello.toString());
}
另一个例子 注意类的引用要使用ref来引入
<bean id="mySqlImpl" class="com.xue.dao.UserDaoMySqlImpl">
</bean>
<bean id="oracleImpl" class="com.xue.dao.UserDaoOracleImpl">
</bean>
<bean id="userServiceImpl" class="com.xue.service.UserServiceImpl">
<property name="userDao" ref="oracleImpl"/>
</bean>
它的实现
@Test
public void UserTest2(){
//拿到容器
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
UserService UserServiceBean = (UserService) context.getBean("userServiceImpl");
UserServiceBean.getUser();
}
4.IOC 构造方法
无参
<bean id="user" class="com.xue.pojo.User">
<property name="name" value="name1"/>
</bean>
<bean id="user2" class="com.xue.pojo.User">
</bean>
无论是否赋予参数 都会是调用无参的构造方式
有参构造
构造函数参数索引
您可以使用该index属性来明确指定构造函数参数的索引,如以下示例所示:
<!-- 下标赋值 -->
<bean id="user3" class="com.xue.pojo.User">
<constructor-arg index="0" value="xx"/>
</bean>
再这里我们进行了测试假如说我们仅仅传入了的是单个参数 则会自动匹配单个参数的构造方法
<bean id="user3" class="com.xue.pojo.User">
<constructor-arg index="0" value="1"/>
<constructor-arg index="1" value="xx"/>
</bean>
如果我们传入了两个参数,则会自动调用两个参数的set方法来进行构造
注意!
public User(int id) {
this.id = id;
System.out.println("User的有参构造 ID 一个参数");
}
public User(String name) {
this.name = name;
System.out.println("User的有参构造 name 一个参数");
}
假如说我们再构造的pojo具有两个这种对象,编译器并不会报错,但是再构造单个的参数的时候,将会出现一定的歧义
构造函数参数类型匹配(不推荐)
在上述情况下,如果通过使用type
属性显式指定构造函数参数的类型,则容器可以使用简单类型的类型匹配,如以下示例所示:
<bean id="exampleBean" class="examples.ExampleBean">
<constructor-arg type="int" value="7500000"/>
<constructor-arg type="java.lang.String" value="42"/>
</bean>
明显这里同样和上面一样,也会出现歧义
构造函数参数名称(推荐)
您还可以使用构造函数参数名称来消除歧义,如以下示例所示:
<bean id="exampleBean" class="examples.ExampleBean">
<constructor-arg name="years" value="7500000"/>
<constructor-arg name="ultimateAnswer" value="42"/>
</bean>
推荐这种方法,其中name是参数的名字
其他
有趣的是,容器里无论你是否需要他,他都会被调用。
并且调用的都是一份,且被初始化完毕。
通过实验可以晓得
User user2 = (User) context.getBean("user3");
User user3 = (User) context.getBean("user3");
System.out.println(user2 == user3); //true
User user2 = (User) context.getBean("user3");
User user3 = (User) context2.getBean("user3");
System.out.println(user2 == user3); //false
所以看起来这种方法更像是我每次都会把xml变成一个类,用get来获取类中的已经构造好的内容。
5.Spring 的配置
别名
<alias name="user3" alias="user"/>
别名就是 把user可以等同于user3 在我看来作用不是很大
<bean id="user3" class="com.xue.pojo.User" name="user2,user,user4">
<constructor-arg index="0" value="1"/>
</bean>
这里name也是别名,可能比alias有更多一定的别名
import
<import resource="beans2.xml"/>
<import resource="beans.xml"/>
假如是项目多人开发,则可以import为一个总的 会存在id覆盖
6 DI 依赖注入
构造器注入
跟上面一样
set注入**
依赖注入
依赖,既bean对象的创建依赖于容器
注入,bean对象的所有属性,由容器来注入
这里做个回顾
mybatis用于数据库的连接和操作,即来作用于dao层的
spring在这里作用于pojo 即bean层
完善注入信息
<bean id="address" class="com.xue.pojo.Address">
<property name="address" value="s"/>
</bean>
<!--最普通的值-->
<bean id="student" class="com.xue.pojo.Student">
<property name="name" value="myName"/>
<!-- ref注入 -->
<property name="address" ref="address"/>
<!-- 数组注入 -->
<property name="book">
<array>
<value>红楼梦</value>
<value>三国</value>
<value>西游记</value>
<value>水浒传</value>
</array>
</property>
<!-- list -->
<property name="hobbies">
<list>
<value>听课</value>
<value>看电影</value>
<value>睡觉</value>
</list>
</property>
<!-- map -->
<property name="card">
<map>
<entry key="key1" value="value1"/>
<entry key="key2" value="value1"/>
<entry key="key3" value="value1"/>
</map>
</property>
<!--set-->
<property name="games">
<set>
<value>LOL</value>
<value>AAA</value>
</set>
</property>
<!--null-->
<!-- <property name="info">-->
<!-- <null/>-->
<!-- </property>-->
<property name="info">
<props>
<prop key="学号">123</prop>
<prop key="性别">男性</prop>
</props>
</property>
</bean>
拓展方式:
有p命名空间和c命名空间两种
<!--
导入p标签
xmlns:p="http://www.springframework.org/schema/p"
便可以使用:
p:name="xx" p:id="4"
类似于
<property name="xx" value="s"/>
-->
<bean id="user" class="com.xue.pojo.User" p:name="xx" p:id="4"/>
<!--
导入p标签
xmlns:c="http://www.springframework.org/schema/c"
便可以使用:
c:name="xxx" c:id="sss"
类似于
<constructor-arg name="name" value="xxx"/>
-->
<bean id="user2" class="com.xue.pojo.User" c:name="xxx" c:id="sss"/>
<bean id="user3" class="com.xue.pojo.User">
<constructor-arg name="name" value="xxx"/>
</bean>
注意P命名和C命名需要导入XML的约束
bean的作用域
Scope | Description |
---|---|
singleton | (Default) Scopes a single bean definition to a single object instance for each Spring IoC container. |
prototype | Scopes a single bean definition to any number of object instances. |
request | Scopes a single bean definition to the lifecycle of a single HTTP request. That is, each HTTP request has its own instance of a bean created off the back of a single bean definition. Only valid in the context of a web-aware Spring ApplicationContext . |
session | Scopes a single bean definition to the lifecycle of an HTTP Session . Only valid in the context of a web-aware Spring ApplicationContext . |
application | Scopes a single bean definition to the lifecycle of a ServletContext . Only valid in the context of a web-aware Spring ApplicationContext . |
websocket | Scopes a single bean definition to the lifecycle of a WebSocket . Only valid in the context of a web-aware Spring ApplicationContext . |
<!--
单例模式,即 每次出来的都是 一个
Student student = (Student) context.getBean("student");
Student student2 = (Student) context.getBean("student");
student==student2
-->
<bean id="user" class="com.xue.pojo.User" p:name="xx" p:id="4" scope="singleton"/>
<!--
·原型模式,即 每次出来的都是 一个心得对象
Student student = (Student) context.getBean("student");
Student student2 = (Student) context.getBean("student");
student!=student2
-->
<bean id="user" class="com.xue.pojo.User" p:name="xx" p:id="4" scope="prototype"/>
7 Bean的自动装配
- spring会在上下文自动的寻找
- 自动装配是Spring满足bean的一种方式
spring三种装配
- 在xml中显示配置
- 在java中配置
- 隐式的自动装配
测试代码:
一个人,有两个宠物
<bean id="cat" class="xue.pojo.Cat"/>
<bean id="dog" class="xue.pojo.Dog"/>
<bean id="people" class="xue.pojo.People">
<property name="name" value="xxx"/>
<property name="cat" ref="cat"/>
<property name="dog" ref="dog"/>
</bean>
ByName自动装配
<bean id="cat" class="xue.pojo.Cat"/>
<bean id="dog" class="xue.pojo.Dog"/>
<bean id="people" class="xue.pojo.People" autowire="byName">
<property name="name" value="xxx"/>
</bean>
会自动查找和自己的对象,在上下文一致的方法。
ByType
<bean id="cat" class="xue.pojo.Cat"/>
<bean id="dog" class="xue.pojo.Dog"/>
<bean id="people" class="xue.pojo.People" autowire="byType">
<property name="name" value="xxx"/>
</bean>
上面两个各有弊端,其中第一个弊端就是,名字一定要上下文一样,类型则是上下文的类只能有一个
使用注解装配
基于注释的配置的引入提出了一个问题,即这种方法是否比XML“更好”。简短的答案是“取决于情况”。长的答案是每种方法都有其优缺点,通常,由开发人员决定哪种策略更适合他们。由于定义方式的不同,注释在声明中提供了很多上下文,从而使配置更短,更简洁。但是,XML擅长连接组件而不接触其源代码或重新编译它们。一些开发人员更喜欢将布线放置在靠近源的位置,而另一些开发人员则认为带注释的类不再是POJO,而且,配置变得分散并且难以控制。
使用注解须知
1.导入约束 context:annotation-config/
2.配置注解支持
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns="http://www.springframework.org/schema/beans"
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/context
https://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
</beans>
此后就可以这样
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns="http://www.springframework.org/schema/beans"
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/context
https://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
<bean id="cat" class="xue.pojo.Cat"/>
<bean id="dog" class="xue.pojo.Dog"/>
<bean id="people" class="xue.pojo.People"/>
</beans>
@Autowired
Cat cat;
@Autowired
Dog dog;
String name;
@Autowired
这个这么使用
@Autowired
Cat cat;
我们来看一下特殊的情况
假如是xml中存在两个名字不一致的,类型一样的cat会如何
expected single matching bean but found 2: cat1,cat2
报错,找到了两个
这个时候我们来改变一个
<bean id="cat" class="xue.pojo.Cat">
<property name="name" value="cat1"/>
</bean>
<bean id="cat2" class="xue.pojo.Cat">
<property name="name" value="cat2"/>
</bean>
People{cat=Cat{name='cat1'}, dog=Dog{name='doog2'}, name='null'}
正常输入id一致的
<bean id="cat" class="xue.pojo.Dog">
<property name="name" value="cat1"/>
</bean>
<bean id="cat2" class="xue.pojo.Cat">
<property name="name" value="cat2"/>
</bean>
结果为:
expected single matching bean but found 2: cat,dog
报错
所以说
先会去根据名字来查找,如果查到了名字直接使用,并不会验证类型是否一致,如果要是查不到名字则会类型来获取,但是如果这时有多个类型则会直接报错
@Qualifier
@Qualifier(value = "cat1")
Cat cat;
自动装配,假如说无法通过Name Or Type来获取到的时候 可以使用Qualifier来指定
@Resource
@Resource
Dog dog;
<bean id="dog2" class="xue.pojo.Dog">
<property name="name" value="doog2"/>
</bean>
<bean id="dog1" class="xue.pojo.Dog">
<property name="name" value="doog1"/>
</bean>
No qualifying bean of type ‘xue.pojo.Dog’ available: expected single matching bean but found 2: dog2,dog1
<bean id="dog2" class="xue.pojo.Dog">
<property name="name" value="doog2"/>
</bean>
<bean id="dog" class="xue.pojo.Dog">
<property name="name" value="doog1"/>
</bean>
这个输出结果是
doog1
<bean id="dog2" class="xue.pojo.Dog">
<property name="name" value="doog2"/>
</bean>
<bean id="dog" class="xue.pojo.Cat">
<!-- <property name="name" value="doog1"/>-->
</bean>
这个直接就会进行报错
所以说我们的出来一个结论 在使用 @Resource开发时 先会去根据名字来查找,如果查到了名字直接使用,并不会验证类型是否一致,如果要是查不到名字则会类型来获取,但是如果这时有多个类型则会直接报错
下面是Spring开发文档的内容
从Spring Framework 5.0开始,您还可以使用@Nullable
注释(任何包中的任何注释,例如,javax.annotation.Nullable
来自JSR-305的注释),或仅利用Kotlin内置的null安全支持:
@Nullable
public People(@Nullable String name) {
this.name = name;
}
即允许name为空
request为false则说明我们允许找不到装配,不抛异常
@Autowired(required = false)
Cat cat;
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1ksTUG9c-1620977292083)(C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20210513225933791.png)]
8 使用注解开发
在spring 4之后要使用注解开发,必须要保证注入aop的导入
bean
上一节有
属性
@Component
//Component 等价于一个<bean id="user" class="com.xue.pojo.User"/>
@Component
public class User {
@Value("xue")
public String name;
}
衍生的注解
@component 有几个衍生的注解,在web的开发中
@Controller
@Repository
@Service
自动装配
作用域
@Scope(“singleton”)
小结
xml 的配置文件可以用于任何地方
注解 不是自己类使用不了,维护也很复杂
xml来管理bean
注解负责完成属性的注入
要想要注解生效一定要在xml里增加扫描包
<!-- 指定要扫描的包 -->
<context:component-scan base-package="com.xue"/>
使用Java的方式来配置Spring
如果完全不使用Spring的xml,完全交给Java来实现
JavaConfig变成了新的功能
@Configuration
9 代理模式
为什么要学代理模式?Spring AOP 的底层
分为静态代理和动态代理
静态代理
角色分析
抽象角色:用接口或者抽象类来解决
真实角色:被代理的角色
代理角色:代理真实的角色,代理角色后,我们一般做一些附属操作
代理模式的好处
可以让用户的操作更加纯粹
可以实现分工
方便扩展
缺点
一个角色会形成一个代理对象,但是代码的量会增加。
动态代理
动态代理和静态代理角色是一样的
动态代理的代理类是动态生成的,不是直接写出来的
1 基于接口 JDK
2 基于类
3 基于Java ssist
两个类
proxy
InvocationHandler
-
InvocationHandler 每个代理实例都有一个关联的调用处理程序。 当在代理实例上调用方法时,方法调用将被编码并分派到其调用处理程序的
invoke
方法。 -
-
Modifier and Type Method and Description Object
invoke(Object proxy, 方法 method, Object[] args)
处理代理实例上的方法调用并返回结果。
-
-
Proxy
提供了创建动态代理类和实例的静态方法,它也是由这些方法创建的所有动态代理类的超类。为某个接口创建代理
Foo
:InvocationHandler handler = new MyInvocationHandler(...); Class<?> proxyClass = Proxy.getProxyClass(Foo.class.getClassLoader(), Foo.class); Foo f = (Foo) proxyClass.getConstructor(InvocationHandler.class). newInstance(handler);
或更简单地:
Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(), new Class<?>[] { Foo.class }, handler);
代理类
public class ProxyInvocationHandler implements InvocationHandler {
private Object target;
public Object getTarget() {
return target;
}
public void setTarget(Object target) {
this.target = target;
}
//得到代理类
public Object getProxy() {
return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//这样就会得到一个
Object result = method.invoke(target, args);
return result;
}
}
10 AOP
让我们首先定义一些重要的AOP概念和术语。这些术语不是特定于Spring的。不幸的是,AOP术语并不是特别直观。但是,如果Spring使用其自己的术语,那将更加令人困惑。
- 方面:跨多个类的关注点的模块化。事务管理是企业Java应用程序中横切关注的一个很好的例子。在Spring AOP中,方面是通过使用常规类(基于模式的方法)或使用注释进行
@Aspect
注释的常规类 (@AspectJ样式)来实现的。 - 连接点:在程序执行过程中的一点,例如方法的执行或异常的处理。在Spring AOP中,连接点始终代表方法的执行。
- 建议:方面在特定的连接点处采取的操作。不同类型的建议包括“周围”,“之前”和“之后”建议。(建议类型将在后面讨论。)包括Spring在内的许多AOP框架都将建议建模为拦截器,并在联接点周围维护一连串的拦截器。
- 切入点:与连接点匹配的谓词。建议与切入点表达式关联,并在与该切入点匹配的任何连接点处运行(例如,执行具有特定名称的方法)。切入点表达式匹配的连接点的概念是AOP的核心,默认情况下,Spring使用AspectJ切入点表达语言。
- 简介:代表类型声明其他方法或字段。Spring AOP允许您向任何建议的对象引入新的接口(和相应的实现)。例如,您可以使用简介来使Bean实现
IsModified
接口,以简化缓存。(在AspectJ社区中,介绍被称为类型间声明。) - 目标对象:一个或多个方面建议的对象。也称为“建议对象”。由于Spring AOP是使用运行时代理实现的,因此该对象始终是代理对象。
- AOP代理:由AOP框架创建的对象,用于实施方面合同(建议方法执行等)。在Spring Framework中,AOP代理是JDK动态代理或CGLIB代理。
- 编织:将方面与其他应用程序类型或对象链接以创建建议的对象。这可以在编译时(例如,使用AspectJ编译器),加载时或在运行时完成。像其他纯Java AOP框架一样,Spring AOP在运行时执行编织。
基于XML的AOP
导入的包
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.6</version>
</dependency>
声明
可以使用<aop:aspect>
元素声明一个方面,并使用ref
属性来引用支持Bean ,如以下示例所示:
<aop:config>
<aop:aspect id="myAspect" ref="aBean">
...
</aop:aspect>
</aop:config>
<bean id="aBean" class="...">
...
</bean>
声明切入点
您可以在<aop:config>
元素内声明一个命名的切入点,从而使切入点定义可以在多个方面和顾问程序之间共享。
可以定义代表服务层中任何业务服务的执行的切入点:
<aop:config>
<aop:pointcut id="businessService"
expression="execution(* com.xyz.myapp.service.*.*(..))"/>
</aop:config>
宣告
<!--使用API接口-->
<!-- 配置AOP -->
<aop:config>
<!-- 需要一个切入点 expression 要切入的位置(要执行的位置!修饰词,返回值 类名 方法名 参数) -->
<aop:pointcut id="pointcut1" expression="execution(* com.xue.service.UserServiceImpl.*(..) )"/>
<!--执行环绕增强-->
<aop:advisor advice-ref="log" pointcut-ref="pointcut1"/>
<aop:advisor advice-ref="afterLog" pointcut-ref="pointcut1"/>
</aop:config>
测试
public class Mytest {
public static void main(String[] args) {
//获取
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = (UserService) context.getBean("userService");
userService.add();
}
}
方法二 用一个类
就是在宣告的时候更改一下
<!-- 方式二 -->
<bean id="diy" class="com.xue.diy.DiyPointCut"/>
<aop:config>
<!-- 设置切面 这里这个ref就是我们要把那个类切入 -->
<aop:aspect ref="diy">
<!-- 切入点 -->
<aop:pointcut id="point" expression="execution(*com.xue.service.UserServiceImpl.*(..))"/>
<aop:before method="before" pointcut-ref="point"/>
<aop:after method="after" pointcut-ref="point"/>
</aop:aspect>
public class DiyPointCut {
public void before() {
System.out.println("===========before============");
}
public void after() {
System.out.println("==========after=============");
}
}
11 整合Mybtis
环境配置
jar包
mybatis
mysql
spring
aop
mybatis-spring
方法
Mybatis-Spring 方法一
MyBatis-Spring 会帮助你将 MyBatis 代码无缝地整合到 Spring 中。它将允许 MyBatis 参与到 Spring 的事务管理之中,创建映射器 mapper 和 SqlSession
并注入到 bean 中,以及将 Mybatis 的异常转换为 Spring 的 DataAccessException
。 最终,可以做到应用代码不依赖于 MyBatis,Spring 或 MyBatis-Spring。
关于Spring来接管MyBatis
Mybatis原有的数据源将会被接管
只需要 建立一个 Mybatis-dao.xml 随后将xml引入到 完整的xml中即可
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:c="http://www.springframework.org/schema/aop"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<aop:aspectj-autoproxy/>
<context:annotation-config/>
<!-- 指定要扫描的包 -->
<context:component-scan base-package="com.xue"/>
<!-- DataSource : 使用Spring Mybatis来替换 -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.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="1111"/>
</bean>
<!-- sql Session -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<!-- 绑定Mybatis配置文件 -->
<property name="configLocation" value="mybatis-config.xml"/>
</bean>
<!-- sqlSession -->
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg index="0" ref="sqlSessionFactory"/>
</bean>
</beans>
这样就可以完成连接的建立这个过程并且完成了之前的获取sqlsession这个工具类的步骤,利用的是SqlSessionTemplate来实现
接下来来个测试!
假如说存在Teahcer 表在数据库中
我们要获取表的数据
在MyBatis中
- 创建pojo
- 做一个mapper的接口与实现它的xml文件
- 利用工具类来获取sqlsession,随后获取 xml所实现的方法,然后再使用方法,来获取数据
(具体代码不再赘述)
在MyBatis-Spring中不同,因为工具类获取sqlsession已经被Spring给接管了,我们可以尝试做一个AOP(我理解的叫AOP)来进行操作
即我们不用xml来实现单一的实现接口而改用一个类来实现接口,随后再用这个类来实现xml文件,我们只需要把我们到的sqlsession注入到这个类中,就可以了。像下面这样:
<bean id="teacherMapper" class="com.xue.mapper.TeacherMapperImpl">
<property name="sqlSession" ref="sqlSession"/>
</bean>
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IbPEVOJK-1620977292089)(…/…/未命名文件(2)].png)
然后它的impl可以是
public class TeacherMapperImpl implements TeacherMapper{
//设置一下将要注入的session
private SqlSessionTemplate sqlSession;
public SqlSessionTemplate getSqlSession() {
return sqlSession;
}
public void setSqlSession(SqlSessionTemplate sqlSession) {
this.sqlSession = sqlSession;
}
@Override
public List<Teacher> queryTeacher() {
//获取要操作的Mapper
TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);
//这个时候 这个mapper已经是实现了TeacherMapper.xml 这个文件里的方法
return mapper.queryTeacher();
}
}
测试类可以是:
public class MyTest {
public static void main(String[] args) throws IOException {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
TeacherMapper userMapper = (TeacherMapper) context.getBean("teacherMapper");
List<Teacher> queryUser = userMapper.queryTeacher();
queryUser.forEach(System.out::println);
}
}
Mybatis-Spring 方法二
终极简化版本
SqlSessionDaoSupport
SqlSessionDaoSupport
是一个抽象的支持类,用来为你提供 SqlSession
。调用 getSqlSession()
方法你会得到一个 SqlSessionTemplate
,之后可以用于执行 SQL 方法,就像下面这样:
public class UserDaoImpl extends SqlSessionDaoSupport implements UserDao {
public User getUser(String userId) {
return getSqlSession().selectOne("org.mybatis.spring.sample.mapper.UserMapper.getUser", userId);
}
}
在这个类里面,通常更倾向于使用 MapperFactoryBean
,因为它不需要额外的代码。但是,如果你需要在 DAO 中做其它非 MyBatis 的工作或需要一个非抽象的实现类,那么这个类就很有用了。
SqlSessionDaoSupport
需要通过属性设置一个 sqlSessionFactory
或 SqlSessionTemplate
。如果两个属性都被设置了,那么 SqlSessionFactory
将被忽略。
假设类 UserMapperImpl
是 SqlSessionDaoSupport
的子类,可以编写如下的 Spring 配置来执行设置:
<bean id="userDao" class="org.mybatis.spring.sample.dao.UserDaoImpl">
<property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>
这是一个化简的方法
这样的话我们可以省去sqlsession注入SqlSessionTemplate这个过程
12 事务
- 原子性
- 隔离性
- 一致性
- 持久性
要开启 Spring 的事务处理功能,在 Spring 的配置文件中创建一个 DataSourceTransactionManager
对象:
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<constructor-arg ref="dataSource" />
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<constructor-arg ref="dataSource"/>
</bean>
<!-- 设置切入点 -->
<!-- 配置事务通知 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<!-- 给那些方法配置事务 propagation 事务的属性 -->
<tx:attributes>
<tx:method name="add" propagation="REQUIRED"/>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<!-- 配置事务的切入 -->
<aop:config>
<aop:pointcut id="txPointcut" expression="(execution(* com.xue.mapper.*(..)))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"></aop:advisor>
</aop:config>
配置来执行设置:
```
这是一个化简的方法
这样的话我们可以省去sqlsession注入SqlSessionTemplate这个过程
12 事务
- 原子性
- 隔离性
- 一致性
- 持久性
要开启 Spring 的事务处理功能,在 Spring 的配置文件中创建一个 DataSourceTransactionManager
对象:
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<constructor-arg ref="dataSource" />
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<constructor-arg ref="dataSource"/>
</bean>
<!-- 设置切入点 -->
<!-- 配置事务通知 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<!-- 给那些方法配置事务 propagation 事务的属性 -->
<tx:attributes>
<tx:method name="add" propagation="REQUIRED"/>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<!-- 配置事务的切入 -->
<aop:config>
<aop:pointcut id="txPointcut" expression="(execution(* com.xue.mapper.*(..)))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"></aop:advisor>
</aop:config>