Sorry, your browser cannot access this site
This page requires browser support (enable) JavaScript
Learn more >

1、spring优点

  1. Spring是一个开源免费的框架,容器
  2. spring是一个轻量级的框架,非侵入式
  3. 控制反转IOC,面向切面AOP
  4. 对事物的支持,对框架的支持

一句话概括:是一个轻量级的控制反转(IOC)和面向切面(AOP)的容器(框架)。

1.2、组成

image-20200907090905978

Spring框架是一个分层架构,由7个定义良好的模块组成。Spring模块构建在核心容器之上,核心容器定义了创建、配置和管理bean的方式。

image-20200907091554005

组成Spring框架的每个模块(或组件)都可以单独存在,或者与其他一个或多个模块联合实现。每个模块的功能如下。

  • 核心容器:核心容器提供Spring框架的基本功能。核心容器的主要组件是BeanFactory使用控制反转(IOC)模式将应用程序的配置和依赖范围与实际的应用程序代码分开。
  • Spring 上下文:Spring上下文是一个配置文件,向Spring框架提供上下文信息。Spring上下文包括企业服务,例如JNDI、EJB、电子邮件、国际化、校验和调度功能。
  • Spring AOP:通过配置管理特性,SpringAOP模块直接将面向切面的编程功能,集成到了Spring框架中。所以,可以很容易地使Spring框架管理任何支持AOP的对象。SpringAOP模块为基于Spring的应用程序中的对象提供了事物管理服务。通过使用SpringAOP,不用依赖组件,就可以将声明性事务管理集成到应用程序中。
  • Spring DAO:JDBC DAO抽象层提供了有意义的异常层次结构,可用该结构来管理异常处理和不同数据库供应商抛出的错误信息。异常层次结构简化了错误处理,并且极大的降低了需要编写的异常代码数量(例如打开和关闭链接)。Spring DAO的面向JDBC的异常遵从通用的DAO异常层次结构。
  • Spring ORM:Spring框架插入了若干个ORM框架,从而提供了ORM的对象关系工具,其中包括JDO、Hibernate和MyBatis。所有这些都遵从Spring的通用事物和DAO异常层次结构。
  • Spring Web模块:Web上下文模块建立在应用程序上下文模块之上,为基于Web的应用程序提供了上下文。所以,Spring框架支持与Jakarta Struts的集成。Web模块还简化了处理多部分请求以及将请求参数绑定到域对象的工作。
  • Spring MVC框架:MVC框架是一个全功能的构建Web应用程序的MVC实现。通过策略接口,MVC框架变为高度可配置的,MVC容纳了大量视图技术,其中包括JSP、Velocity、Tiles、iText和POI。

2、IOC基础

这是我们以前写代码的方式:

  1. 先写一个UserDao接口

    1
    2
    3
    public interface UserDao {
    public void getUser();
    }
  2. 再写Dao的实现类

    1
    2
    3
    4
    5
    6
    public class UserDaoImpl implements UserDao {
    @Override
    public void getUser() {
    System.out.println("获取用户数据");
    }
    }
  3. 然后写UserService的接口

    1
    2
    3
    public interface UserService {
    public void getUser();
    }
  4. 最后写Service的实现类

    1
    2
    3
    4
    5
    6
    7
    8
    public class UserServiceImpl implements UserService {
    private UserDao userDao = new UserDaoImpl();

    @Override
    public void getUser() {
    userDao.getUser();
    }
    }

这是我们最初始的方式,但是假如需求发生变化,需要在UserDao的实现类增加一个。

1
2
3
4
5
6
public class UserDaoMySqlImpl implements UserDao {
@Override
public void getUser() {
System.out.println("MySql获取用户数据");
}
}

紧接着我们要去使用Mysql的话,我们就需要去service实现类里面修改对应的实现

1
2
3
4
5
6
7
8
public class UserServiceImpl implements UserService {
private UserDao userDao = new UserDaoMySqlImpl();

@Override
public void getUser() {
userDao.getUser();
}
}

再假设,我们的需求又发生变化又要增加一个UserDao的实现类。

1
2
3
4
5
6
public class UserDaoOracleImpl implements UserDao {
@Override
public void getUser() {
System.out.println("Oracle获取用户数据");
}
}

之后我们又需要去service实现类里面修改对应的实现,假设我们类似的需求比较多,这就需要我们修改大量的代码,这种设计的耦合性太高了。

那我们应该如何解决呢?

我们可以在需要用到他的地方,不去实现它,而是留出一个接口,利用set。

1
2
3
4
5
6
7
8
9
10
11
12
public class UserServiceImpl implements UserService {
private UserDao userDao;
// 利用set实现
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}

@Override
public void getUser() {
userDao.getUser();
}
}

然后进行测试一下

1
2
3
4
5
6
7
8
9
10

@Test
public void test(){
UserServiceImpl service = new UserServiceImpl();
service.setUserDao( new UserDaoMySqlImpl() );
service.getUser();
//那我们现在又想用Oracle去实现呢
service.setUserDao( new UserDaoOracleImpl() );
service.getUser();
}

运行起来没有什么区别,但是这个已经发生了根本性的变化,很多地方都不一样了,原来的方式,所有的东西是由程序去进行控制创建,而现在是由我们自行控制创建对象,把主动权交给了调用者,程序不用去管怎么创建,怎么实现,它现在只负责提供一个接口。

这种思想,从本质上解决了问题,我们程序员不再去管理对象的创建了,更多的去关注业务的实现,耦合性大大降低,这也就是IOC的原型。

3、IOC本质

控制反转(IOC)是一种设计思想,DI(依赖注入)是实现的IOC的一种方法,也有人认为DI只是IOC的另一种说法。没有IOC的程序中,我们使用面向对象编程,对象的创建由程序自己控制,控制反转后将对象的创建转移给第三方,个人认为所谓的控制反转就是:获得对象的方式反转了。

image-20200907104656586

IOC是Spring框架的核心内容,使用多种方式完美的实现了IOC,可以使用XM配置,也可以使用注解,新版的Spring也可以零配置实现IOC。

Spring容器在初始化时先读取配置文件,根据配置文件或元数据创建与组织对象存入容器中,程序使用时再从IOC容器中取出需要的对象。

image-20200907105115521

采用XML方式配置Bean的时候,Bean的定义信息是和现实分离的,而采用注解的方式可以把两者合为一体,Bean的定义信息直接以注解的形式定义在实现类中,从而达到了零配置的目的。

控制反转是一种通过描述(XML或注解)并通过第三方去生产或获取特定对象的方式。在Spring中实现控制反转的是IOC容器,其实方式是依赖注入(DI)。

3.1、IOC实例

1、首先在maven中导入依赖

1
2
3
4
5
6
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.7.RELEASE</version>
</dependency>

2、创建一个实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package pojo;

public class Hello {

private String str;

public String getStr() {
return str;
}

public void setStr(String str) {
this.str = str;
}

@Override
public String toString() {
return "Holle [str=" + str + "]";
}
}

3、在resource里面创建一个xml文件,文件头可去spring官方文档中取

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?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">


<!--在Spring中创建对象,在Spring这些都称为bean
类型 变量名 = new 类型();
Holle holle = new Holle();

bean = 对象(holle)
id = 变量名(holle)
class = new的对象(new Holle();)
property 相当于给对象中的属性设值,让str="Spring"
-->

<bean id="hello" class="pojo.Hello">
<property name="str" value="Spring"/>
</bean>
</beans>

4、创建一个测试类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package holle1;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import pojo.Hello;

public class MyTest {

public static void main(String[] args) {
//获取Spring的上下文对象
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
//我们的对象下能在都在spring·中管理了,我们要使用,直接取出来就可以了
Hello holle = (Hello) context.getBean("hello");
System.out.println(holle.toString());
}

}

核心是利用了set方法注入,所以必须要有set方法。

思考:

  • Hello对象是谁创建的? 是由Spring创建的
  • Hello对象的属性是怎么设置的? 是由Spring容器设置的

这个过程就叫控制翻转

控制:谁来控制对象的创建,传统应用程序的对象是由程序本身控制的,使用Spring后,对象是由Spring来创建的。

翻转:程序本身不创建对象,而被动的接受对象。

IOC是一种编程思想,由主动的编程变成被动的接受。

4、IOC创建对象的方式

1、使用无参构造穿件对象,默认方式

2、使用有参构造(如下)

下标赋值

1
2
3
4
5
6
7
8
9
10
<?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="user" class="pojo.User">
<constructor-arg index="0" value="chen"/>
</bean>
</beans>

类型赋值(不建议使用)

1
2
3
<bean id="user" class="pojo.User">
<constructor-arg type="java.lang.String" value="kuang"/>
</bean>

直接通过参数名(常用)

1
2
3
4
<bean id="user" class="pojo.User">
<constructor-arg name="name" value="kuang"></constructor-arg>
</bean>
<!-- 比如参数名是name,则有name="具体值" -->

注册的对象已被初始化,并且默认创建模式为单例模式。

5、Spring配置

1、别名

1
2
3
4
5
6
7
8
<bean id="user" class="pojo.User">
<constructor-arg name="name" value="chen"></constructor-arg>
</bean>

<alias name="user" alias="userLove"/>
<!-- 使用时
User user2 = (User) context.getBean("userLove");
-->

2、注册bean的配置

1
2
3
4
5
6
7
8
9
<!--id:bean的唯一标识符,也就是相当于我们学的对象名
class:bean对象所对应的会限定名:包名+类型
name:也是别名,而且name可以同时取多个别名 -->
<bean id="user" class="pojo.User" name="u1 u2,u3;u4">
<property name="name" value="chen"/>
</bean>
<!-- 使用时
User user2 = (User) context.getBean("u1");
-->

3、import

import一般用于团队开发,可以将多个配置文件导入合并为一个

假设,现在项目中有多个人开发,这三个人复制不同的类开发,不同的类需要注册在不同的bean中,我们可以利
用import将所有人的beans.xml合并为一个总的!

  • 张三(beans.xm1)

  • 李四(beans2.xm1)

  • 王五(beans3.xm1)

1
2
3
<import resource="beans.xm1"/>
<import resource="beans2.xml"/>
<import resource="beans3.xm1"/>

并且如果合并的文件中,有重复的bean也会合并。

6、bean各种类型的注入

首先创建一个复杂的类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package pojo;

import java.util.*;
@Get
@Set
public class Student {
//别忘了写get和set方法(用lombok注解也行)
private String name;
private Address address;

private String[] books;
private List<String> hobbies;

private Map<String, String> card;
private Set<String> game;

private Properties infor;
private String wife;

@Override
public String toString() {
return "Student{" +"\n"+
"name='" + name + '\'' +"\n"+
", address=" + address.toString() +"\n"+
", books=" + Arrays.toString(books) +"\n"+
", hobbies=" + hobbies +"\n"+
", card=" + card +"\n"+
", game=" + game +"\n"+
", infor=" + infor +"\n"+
", wife='" + wife + '\'' +"\n"+
'}';
}
}

Address类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package pojo;

public class Address {

private String address;

public String getAddress() {
return address;
}

public void setAddress(String address) {
this.address = address;
}

@Override
public String toString() {
return "Address{" +
"address='" + address + '\'' +
'}';
}
}

设置bean

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
<?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="address" class="pojo.Address">
<property name="address" value="address你好" />
</bean>

<bean id="student" class="pojo.Student">
<!--第一种,普通值注入 -->
<property name="name" value="name你好" />
<!--第二种,ref注入 -->
<property name="address" ref="address" />

<!--数组注入 -->
<property name="books">
<array>
<value>三国</value>
<value>西游</value>
<value>水浒</value>
</array>
</property>

<!--list列表注入 -->
<property name="hobbies">
<list>
<value></value>
<value></value>
<value>rap</value>
<value>篮球</value>
</list>
</property>

<!--map键值对注入 -->
<property name="card">
<map>
<entry key="username" value="root" />
<entry key="password" value="root" />
</map>
</property>

<!--set(可去重)注入 -->
<property name="game">
<set>
<value>wangzhe</value>
<value>lol</value>
<value>galname</value>
</set>
</property>

<!--空指针null注入 -->
<property name="wife">
<null></null>
</property>

<!--properties常量注入 -->
<property name="infor">
<props>
<prop key="id">20200802</prop>
<prop key="name">cbh</prop>
</props>
</property>
</bean>
</beans>

6.2、bean的作用域

20160417164310654

Spring默认为单例模式,可以通过scope去修改

1
<bean id="user2" class="pojo.User" c:name="cxk" c:age="19" scope="singleton"></bean>

6.3、bean的生命周期

java0-1558500658

如上图所示,Bean 的生命周期还是比较复杂的,下面来对上图每一个步骤做文字描述:

  1. Spring启动,查找并加载需要被Spring管理的bean,进行Bean的实例化
  2. Bean实例化后对将Bean的引入和值注入到Bean的属性中
  3. 如果Bean实现了BeanNameAware接口的话,Spring将Bean的Id传递给setBeanName()方法
  4. 如果Bean实现了BeanFactoryAware接口的话,Spring将调用setBeanFactory()方法,将BeanFactory容器实例传入
  5. 如果Bean实现了ApplicationContextAware接口的话,Spring将调用Bean的setApplicationContext()方法,将bean所在应用上下文引用传入进来。
  6. 如果Bean实现了BeanPostProcessor接口,Spring就将调用他们的postProcessBeforeInitialization()方法。
  7. 如果Bean 实现了InitializingBean接口,Spring将调用他们的afterPropertiesSet()方法。类似的,如果bean使用init-method声明了初始化方法,该方法也会被调用
  8. 如果Bean 实现了BeanPostProcessor接口,Spring就将调用他们的postProcessAfterInitialization()方法。
  9. 此时,Bean已经准备就绪,可以被应用程序使用了。他们将一直驻留在应用上下文中,直到应用上下文被销毁。
  10. 如果bean实现了DisposableBean接口,Spring将调用它的destory()接口方法,同样,如果bean使用了destory-method 声明销毁方法,该方法也会被调用。

7、bean的自动装配

  • 自动装配是Spring满足bean依赖的一种方式
  • Spring会在上下文自动寻找,并自动给bean装配属性

7.1、自动装配

首先建立几个类

Cat

1
2
3
4
5
public class Cat {
public void shut(){
System.out.println("miao~");
}
}

Dog

1
2
3
4
5
6
7
public class Dog {

public void shut(){
System.out.println("wang~");
}

}

People

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
package pojo;
public class People {

private Cat cat;
private Dog dog;
private String name;

public Cat getCat() {
return cat;
}

public void setCat(Cat cat) {
this.cat = cat;
}

public Dog getDog() {
return dog;
}

public void setDog(Dog dog) {
this.dog = dog;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "People{" +
"cat=" + cat +
", dog=" + dog +
", name='" + name + '\'' +
'}';
}
}

xml配置:通过byType自动装配

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?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="cat" class="pojo.Cat"/>
<bean id="dog" class="pojo.Dog"/>

<!--byType会在容器自动查找,和自己对象属性相同的bean
例如,Dog dog; 那么就会查找pojo的Dog类,再进行自动装配
-->
<bean id="people" class="pojo.People" autowire="byType">
<property name="name" value="cbh"></property>
</bean>
</beans>

注意:保证类型唯一,否则报错

xml配置 -> byName 自动装配

1
2
3
4
5
6
7
8
9
<bean id="cat" class="pojo.Cat"/>
<bean id="dog" class="pojo.Dog"/>
<!--byname会在容器自动查找,和自己对象set方法的set后面的值对应的id
例如:setDog(),取set后面的字符作为id,则要id = dog 才可以进行自动装配

-->
<bean id="people" class="pojo.People" autowire="byName">
<property name="name" value="cbh"></property>
</bean>

注意:保证name唯一,否则报错

7.2、使用注解实现自动装配

jdk1.5支持的注解,spring2.5支持的注解

首先要加上context约束

1
2
3
4
5
6
7
8
9
10
11
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">

<context:annotation-config/><!--一定不能忘记-->
</beans>

使用注解@Autowired

默认是byType方式,如果匹配不上,就会byName

1
2
3
4
5
6
7
public class People {
@Autowired
private Cat cat;
@Autowired
private Dog dog;
private String name;
}

@Autowired不能唯一装配时,需要@Autowired+@Qualifier

如果@Autowired自动装配环境比较复杂。自动装配无法通过一个注解完成的时候,可以使用@Qualifier(value = “dog”)去配合使用,指定一个唯一的id对象

1
2
3
4
5
6
7
8
public class People {
@Autowired
private Cat cat;
@Autowired
@Qualifier(value = "dog")
private Dog dog;
private String name;
}

使用注解@Resource

默认是byName方式,如果匹配不上,就会byType

1
2
3
4
5
6
7
public class People {
Resource(name="cat")
private Cat cat;
Resource(name="dog")
private Dog dog;
private String name;
}

区别:

  • 都是用来自动装配的,都可以放在属性字段上
  • @Autowired通过byType的方式实现,而且必须要求这个对象存在!【常用】
  • @Resource默认通过byname的方式实现,如果找不到名字,则通过byType实现!如果两个都找不到的情况下,就报错!【常用】
  • 执行顺序不同:@Autowired通过byType的方式实现。@Resource默认通过byname的方式实现

使用注解@Component

使用此注解就可以不用在xml文件中,装配bean了,因为这个注解就是将对象交给Spring去管理

1
<context:component-scan base-package="com.pojo"/> 

记得在xml文件中开启注解的扫描(有了< context:component-scan>,另一个< context:annotation-config/>标签可以移除掉,因为已经被包含进去了。)

1
2
3
4
5
6
//@Component 组件
//等价于<bean id="user" classs = "pojo.User"/>
@Component
public class User {
public String name ="小明";
}

属性如何注入@value

1
2
3
4
5
6
7
8
9
10
11
12
@Component
public class User {
//相当于<property name="name" value="小明"/>
@value("小明")
public String name;

//也可以放在set方法上面
//@value("小明")
public void setName(String name) {
this.name = name;
}
}

7.3、使用java的方式配置Spring

1
2
3
4
5
6
7
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
@Value("xiao")
private String name;
}

配置文件:使用config中的UserConfig.java

1
2
3
4
5
6
7
@Configuration
public class UserConfig {
@Bean
public User getUser(){
return new User();
}
}

注意:

1
2
3
4
5
6
7
8
public class MyTest { 
public static void main(String[ ] args) {
//如果完全使用了配置类方式去做,我们就只能通过 Annotationconfig 上下文来获取容器,通过配置类的class对象加载!
ApplicationContext context = new AnnotationConfigApplicationContext(UserConfig.Class); //class对象
User getUser =(User)context.getBean( "getUser"); //方法名getUser
System.out.Println(getUser.getName());
}
}

@Import(UserConfig2.class):这个注解作用也是合并配置类

8、静态代理

代理模式是SpringBoot的底层

分类:动态代理和静态代理

静态代理

8.1、静态代理

角色分析:

  • 抽象角色:一般会使用接口或者抽象类来解决
  • 真实角色:被代理的角色
  • 代理角色:代理真实角色,代理真是角色后,我们一般会做一些附庸操作
  • 客户:可以访问代理对象的人

代码实例:

1、接口

1
2
3
4
package pojo;
public interface Host {
public void rent();
}

2、真实角色

1
2
3
4
5
6
7
package pojo;
public class HostMaster implements Host{

public void rent() {
System.out.println("房东要出租房子");
}
}

3、代理角色

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package pojo;
public class Proxy {

public Host host;

public Proxy() {

}

public Proxy(Host host) {
super();
this.host = host;
}

public void rent() {
seeHouse();
host.rent();
fee();
sign();
}
//看房
public void seeHouse() {
System.out.println("看房子");
}
//收费
public void fee() {
System.out.println("收中介费");
}
//合同
public void sign() {
System.out.println("签合同");
}
}

4、客户端访问代理角色

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package holle4_proxy;

import pojo.Host;
import pojo.HostMaster;
import pojo.Proxy;

public class My {

public static void main(String[] args) {
//房东要出租房子
Host host = new HostMaster();
//中介帮房东出租房子,但也收取一定费用(增加一些房东不做的操作)
Proxy proxy = new Proxy(host);
//看不到房东,但通过代理,还是租到了房子
proxy.rent();

}
}

代理模式的好处:

  • 可以使真实角色的操作更加纯粹!不用去关心一些公共的业务
  • 公共事务就交给代理角色,实现了业务的分工
  • 公共事务发生扩展的时候,方便几种管理

缺点:一个真实角色就会产生一个代理角色,代码量会翻倍,开发效率降低

8.2、动态代理

动态代理和静态代理角色一样,动态代理底层就是反射机制

动态代理是动态生成的,不是我们直接写好的

动态代理(两大类):基于接口,基于类

  • 基于接口:jdk的动态代理
  • 基于类:cglib
  • java字节码实现:javaisit

了解两个类

1、Proxy:代理

2、InvocationHandler:调用处理程序

实例代码:

接口:

1
2
3
4
5
6
//接口
package pojo2;
public interface Host {
public void rent();

}

接口实现类

1
2
3
4
5
6
7
//接口实现类
package pojo2;
public class HostMaster implements Host{
public void rent() {
System.out.println("房东要租房子");
}
}

代理角色的处理程序类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
package pojo2;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

///用这个类,自动生成代理
public class ProxyInvocationHandler implements InvocationHandler {

// Foo f =(Foo) Proxy.NewProxyInstance(Foo. Class.GetClassLoader(),
// new Class<?>[] { Foo.Class },
// handler);

// 被代理的接口
public HostMaster hostMaster ;

public void setHostMaster(HostMaster hostMaster) {
this.hostMaster = hostMaster;
}

// 得到生成的代理类
public Object getProxy() {
// newProxyInstance() -> 生成代理对象,就不用再写具体的代理类了
// this.getClass().getClassLoader() -> 找到加载类的位置
// hostMaster.getClass().getInterfaces() -> 代理的具体接口
// this -> 代表了接口InvocationHandler的实现类ProxyInvocationHandler
return Proxy.newProxyInstance(this.getClass().getClassLoader(), hostMaster.getClass().getInterfaces(), this);


// 处理代理实例并返回结果
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
seeHouse();
// 动态代理的本质,就是使用反射机制实现的
// invoke()执行它真正要执行的方法
Object result = method.invoke(hostMaster, args);
fee();
return result;
}

public void seeHouse() {
System.out.println("看房子");
}

public void fee() {
System.out.println("收中介费");
}

}

用户类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package holle4_proxy;

import pojo2.Host;
import pojo2.Host2;
import pojo2.HostMaster;
import pojo2.ProxyInvocationHandler;

public class My2 {

public static void main(String[] args) {

//真实角色
HostMaster hostMaster = new HostMaster();

//代理角色,现在没有;用代理角色的处理程序来实现Host接口的调用
ProxyInvocationHandler pih = new ProxyInvocationHandler();

//pih -> HostMaster接口类 -> Host接口
pih.setHostMaster(hostMaster);

//获取newProxyInstance动态生成代理类
Host proxy = (Host) pih.getProxy();

proxy.rent();

}
}

可以将代理程序类改成一个万能类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
///用这个类,自动生代理
public class ProxyInvocationHandler implements InvocationHandler {

// 被代理的接口
public 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 {
// 动态代理的本质,就是使用反射机制实现的
// invoke()执行它真正要执行的方法
Object result = method.invoke(target, args);
return result;
}

}

9、AOP

9.1、什么是AOP

在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方
式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个
热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑
的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高
了开发的效率。

9.2、AOP在Spring中的使用

  • 提供声明式事务,允许用户自定义切面
  • 横切关注点:跨越应用程序多个模块的方法或功能。即是,与我们业务逻辑无关的,但是我们需要关注的部分,就是横切关注点。如日志,安全,缓存,事务等等…
  • 切面(Aspect):横切关注点 被模块化的特殊对象。即,它是一个类。(Log类)
  • 通知(Advice):切面必须要完成的工作。即,它是类中的一个方法。(Log类中的方法)
  • 目标(Target):被通知对象。(生成的代理类)
  • 代理(Proxy):向目标对象应用通知之后创建的对象。(生成的代理类)
  • 切入点(PointCut):切面通知执行的”地点”的定义。(最后两点:在哪个地方执行,比如:method.invoke())
  • 连接点(JointPoint):与切入点匹配的执行点。

aoop

在SpringAop中,通过Advice定义横切逻辑,Spring中支持5种类型的Advice

advice

即AOP在不改变原有代码的基础上,去实现新的功能

9.3、使用Spring实现AOP

首先导入依赖

1
2
3
4
5
6
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</version>
</dependency>

方法一:使用原生spring接口

在配置文件中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?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">

<!--注册bean-->
<bean id="userservice" class="service.UserServiceImpl"/>
<bean id="log" class="log.Log"/>
<bean id="afterLog" class="log.AfterLog"/>
<!--方式一,使用原生Spring API接口-->
<!--配置aop,还需要导入aop约束-->
<aop:config>
<!--切入点:expression:表达式,execution(要执行的位置)-->
<aop:pointcut id="pointcut" expression="execution(* service.UserServiceImpl.*(..))"/>
<!--UserServiceImpl.*(..) -》 UserServiceImpl类下的所以方法(参数)-->
<!--执行环绕增加-->
<aop:advisor advice-ref="log" pointcut-ref="pointcut"/>
<aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>
<!-- 环绕,在id="pointcut"的前后切入 -->
</aop:config>

</beans>

execution(返回类型,类名,方法名(参数)) -> execution(* com.service.,(…))

UserService.java

1
2
3
4
5
6
7
package service;
public interface UserService {
public void add() ;
public void delete() ;
public void query() ;
public void update();
}

UserService 的实现类 UserServiceImp.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package service;

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 query() {
System.out.println("query查");
}
}

前置Log.java

1
2
3
4
5
6
7
8
9
10
11
12
package log;
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;

public class Log implements MethodBeforeAdvice {
//method:要执行的目标对象的方法
//args:参数
//target:目标对象
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println(target.getClass().getName()+"的"+method.getName()+"被执行了");
}
}

后置AfterLog.java

1
2
3
4
5
6
7
8
9
10
package log;
import java.lang.reflect.Method;
import org.springframework.aop.AfterReturningAdvice;

public class AfterLog implements AfterReturningAdvice {
//returnVaule: 返回值
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println("执行了"+method.getName()+"方法,返回值是"+returnValue);
}
}

测试类

1
2
3
4
5
6
7
8
9
10
11
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import service.UserService;

public class MyTest5 {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = (UserService) context.getBean("userservice");
userService.add();
}
}

方法二:自定义实现AOP

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?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">

<!--注册bean-->
<bean id="userservice" class="service.UserServiceImpl"/>
<bean id="log" class="log.Log"/>
<bean id="afterLog" class="log.AfterLog"/>
<!-- 方式二,自定义 -->
<bean id="diy" class="diy.DiyPointcut"/>
<aop:config>
<!--自定义切面-->
<aop:aspect ref="diy">
<!--切入点-->
<aop:pointcut id="point" expression="execution(* service.UserServiceImpl.*(..))"/>
<aop:before method="before" pointcut-ref="point"/>
<aop:after method="after" pointcut-ref="point"/>
</aop:aspect>
</aop:config>

</beans>
1
2
3
4
5
6
7
8
9
10
11
package diy;
public class DiyPointcut {

public void before(){
System.out.println("插入到前面");
}

public void after(){
System.out.println("插入到后面");
}
}

测试

1
2
3
4
5
6
7
8
9
//测试
public class MyTest5 {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//注意:动态代理代理的是接口
UserService userService = (UserService) context.getBean("userservice");
userService.add();
}
}

方法三:使用注解实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?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">

<!-- 注册 -->
<bean id="userservice" class="service.UserServiceImpl"/>
<!--方式三,使用注解实现-->
<bean id="diyAnnotation" class="diy.DiyAnnotation"></bean>

<!-- 开启自动代理
实现方式:默认JDK (proxy-targer-class="fasle")
cgbin (proxy-targer-class="true")-->
<aop:aspectj-autoproxy/>

</beans>

DiyAnnotation.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package diy;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

@Aspect //标注这个类是一个切面
public class DiyAnnotation {

@Before("execution(* service.UserServiceImpl.*(..))")
public void before(){
System.out.println("=====方法执行前=====");
}

@After("execution(* service.UserServiceImpl.*(..))")
public void after(){
System.out.println("=====方法执行后=====");
}

//在环绕增强中,我们可以给地暖管一个参数,代表我们要获取切入的点
@Around("execution(* service.UserServiceImpl.*(..))")
public void around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("环绕前");

Object proceed = joinPoint.proceed();

System.out.println("环绕后");
}
}

测试

1
2
3
4
5
6
7
8
public class MyTest5 {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//注意:动态代理代理的是接口
UserService userService = (UserService) context.getBean("userservice");
userService.add();
}
}

10、整合mybatis

mybatis的配置流程:

  1. 编写实体类
  2. 编写核心配置文件
  3. 编写接口
  4. 编写Mapper.xmi
  5. 测试

10.1、mybatis-spring方式一

  1. 编写数据源配置
  2. sqISessionFactory
  3. sqISessionTemplate(相当于sqISession)
  4. 需要给接口加实现类【new】
  5. 将自己写的实现类,注入到Spring中
  6. 测试!

首先导入依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
<dependencies>

<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.7.RELEASE</version>
</dependency>

<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</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>

<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.2</version>
</dependency>

<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.4</version>
</dependency>

<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.12</version>
</dependency>

<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
</dependency>

</dependencies>

<!--在build中配置resources,来防止资源导出失败的问题-->
<!-- Maven解决静态资源过滤问题 -->
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>

实体类

1
2
3
4
5
6
7
8
package pojo;
import lombok.Data;
@Data
public class User {
private int id;
private String name;
private String pwd;
}

编写接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package mapper;
import java.util.List;
import org.mybatis.spring.SqlSessionTemplate;
import pojo.User;

public class UserMapperImpl implements UserMapper{

//我们的所有操作,在原来都使用sqlSession来执行,现在都使用SqlSessionTemplate;
private SqlSessionTemplate sqlSessionTemplate;

public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) {
this.sqlSessionTemplate = sqlSessionTemplate;
}

public List<User> getUser() {
UserMapper mapper = sqlSessionTemplate.getMapper(UserMapper.class);
return mapper.getUser();
}
}

编写接口的实现类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package mapper;
import java.util.List;
import org.mybatis.spring.SqlSessionTemplate;
import pojo.User;

public class UserMapperImpl implements UserMapper{

//我们的所有操作,在原来都使用sqlSession来执行,现在都使用SqlSessionTemplate;
private SqlSessionTemplate sqlSessionTemplate;

public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) {
this.sqlSessionTemplate = sqlSessionTemplate;
}

public List<User> getUser() {
UserMapper mapper = sqlSessionTemplate.getMapper(UserMapper.class);
return mapper.getUser();
}
}

编写接口相映的mapper

1
2
3
4
5
6
7
8
9
10
11
<?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="mapper.UserMapper">
<select id="getUser" resultType="pojo.User">
select * from mybatis.mybatis
</select>
</mapper>

mybatis-config.xml(可以省略不写,如果需要额外的配置,将mybatis的配置写在里面)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?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>
<!--开启日志-->
<settings>
<setting name="logImpl" value="STDOUT_LOGGING" />
</settings>

<!--可以给实体类起别名 -->
<typeAliases>
<package name="pojo" />
</typeAliases>

</configuration>

spring-dao.xml(mybatis的主要配置)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<?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">

<!--DataSource:使用Spring的数帮源替换Mybatis的配置 其他数据源:c3p0、dbcp、druid
这使用Spring提供的JDBC: org.springframework.jdbc.datasource -->
<!--data source -->
<bean id="datasource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName"
value="com.mysql.cj.jdbc.Driver" />
<property name="url" value="jdbc:mysql://127.0.0.1:3306/mybatis?useSSL=false&amp;useUnicode=true&amp;characterEncoding=utf-8&amp;serverTimezone=Asia/Shanghai"/>
<property name="username" value="root" />
<property name="password" value="root" />
</bean>

<!--sqlSessionFactory-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="datasource" />
<!--绑定 mybatis 配置文件-->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
<property name="mapperLocations" value="classpath:mapper/*.xml"/>
</bean>

<!-- sqlSessionTemplate 就是之前使用的:sqlsession -->
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<!-- 只能使用构造器注入sqlSessionFactory 原因:它没有set方法-->
<constructor-arg index="0" ref="sqlSessionFactory"/>
</bean>

</beans>

applicationContext.xml (总配置类)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?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">

<!-- 导入spring-dao.xml -->
<import resource="spring-dao.xml"/>

<bean id="userMapper" class="mapper.UserMapperImpl">
<property name="sqlSessionTemplate" ref="sqlSession"></property>
</bean>

</beans>

10.2、mybatis-spring方式二

显现类继承SqlSessionDaoSupport

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package mapper;
import pojo.User;
import org.apache.ibatis.session.SqlSession;
import org.mybatis.spring.support.SqlSessionDaoSupport;
import java.util.List;
//继承SqlSessionDaoSupport 类
public class UserMapperImpl2 extends SqlSessionDaoSupport implements UserMapper {
public List<User> getUser() {
SqlSession sqlSession = getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
return mapper.getUser();
//或者一句话:return getSqlSession().getMapper(UserMapper.class).getUser();
}
}

spring-dao.xml 相应修改

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<?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">

<!--DataSource:使用Spring的数帮源替换Mybatis的配置 c3p0 dbcp druid
这使用Spring提供的JDBC: org.springframework.jdbc.datasource -->
<!--data source -->
<bean id="datasource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName"
value="com.mysql.cj.jdbc.Driver" />
<property name="url" value="jdbc:mysql://127.0.0.1:3306/mybatis?useSSL=false&amp;useUnicode=true&amp;characterEncoding=utf-8&amp;serverTimezone=Asia/Shanghai"/>
<property name="username" value="root" />
<property name="password" value="root" />
</bean>

<!--sqlSessionFactory-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="datasource" />
<!--绑定 mybatis 配置文件-->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
<property name="mapperLocations" value="classpath:mapper/*.xml"/>
</bean>

<!-- 方法二:SqlSessionTemplate 可以不写了-->

</beans>

applicationContext.xml(相应的bean 参数修改)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?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="userMapper2" class="mapper.UserMapperImpl2">
<property name="sqlSessionFactory" ref="sqlSessionFactory"></property>
</bean>
</beans>

11、声明式事务

  • 把一组业务当成一个业务来做;要么都成功,要么都失败!
  • 事务在项目开发中,十分的重要,涉及到数据的一致性问题
  • 确保完整性和一致性

事务的ACID原则:
1、原子性
2、隔离性
3、一致性
4、持久性

Spring中的事务管理

  • 声明式事务:AOP
  • 编程式事务:需要再代码中,进行事务管理

声明式事务:

首先导入依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
<dependencies>

<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.7.RELEASE</version>
</dependency>

<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</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>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.2</version>
</dependency>

<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.4</version>
</dependency>

<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.12</version>
</dependency>

<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
</dependency>

</dependencies>

<!--在build中配置resources,来防止资源导出失败的问题-->
<!-- Maven解决静态资源过滤问题 -->
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>

实体类

1
2
3
4
5
6
7
8
9
10
11
12
13
package pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private int id;
private String name;
private String pwd;
}

编写mapper接口

1
2
3
4
5
6
7
8
9
10
11
12
package mapper;
import java.util.List;
import org.apache.ibatis.annotations.Param;
import pojo.User;

public interface UserMapper {
public List<User> getUser();

public int insertUser(User user);

public int delUser(@Param("id") int id);
}

编写mapper实现类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package mapper;

import pojo.User;
import org.apache.ibatis.session.SqlSession;
import org.mybatis.spring.support.SqlSessionDaoSupport;
import java.util.List;

public class UserMapperImpl extends SqlSessionDaoSupport implements UserMapper {
public List<User> getUser() {
User user = new User(5,"你好","ok");
insertUser(user);
delUser(5);
SqlSession sqlSession = getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
return mapper.getUser();
//或者return getSqlSession().getMapper(UserMapper.class).getUser();
}
//插入
public int insertUser(User user) {
return getSqlSession().getMapper(UserMapper.class).insertUser(user);
}
//删除
public int delUser(int id) {
return getSqlSession().getMapper(UserMapper.class).delUser(id);
}
}

mapper的xml文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?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="mapper.UserMapper">
<select id="getUser" resultType="pojo.User">
select * from mybatis.mybatis
</select>

<insert id="insertUser" parameterType="pojo.User" >
insert into mybatis.mybatis (id,name,pwd) values (#{id},#{name},#{pwd})
</insert>

<delete id="delUser" parameterType="_int">
deleteAAAAA from mybatis.mybatis where id = #{id}
<!-- deleteAAAAA是故意写错的 -->
</delete>

</mapper>

mybatis-config.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?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 -->
<configuration>

<!--开启日志-->
<settings>
<setting name="logImpl" value="STDOUT_LOGGING" />
</settings>

<!--可以给实体类起别名-->
<typeAliases>
<package name="pojo" />
</typeAliases>

</configuration>

spring-dao.xml(已导入约束)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
<?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/tx
https://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">

<!--data source -->
<bean id="datasource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName"
value="com.mysql.cj.jdbc.Driver" />
<property name="url" value="jdbc:mysql://127.0.0.1:3306/mybatis?useSSL=false&amp;useUnicode=true&amp;characterEncoding=utf-8&amp;serverTimezone=Asia/Shanghai"/>
<property name="username" value="root" />
<property name="password" value="root" />
</bean>

<!--sqlSessionFactory-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="datasource" />
<!--绑定 mybatis 配置文件-->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
<property name="mapperLocations" value="classpath:mapper/*.xml"/>
</bean>

<!--声明式事务-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<constructor-arg ref="datasource" />
</bean>

<!--结合aop实现事务织入-->
<!--配置事务的通知类-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<!--给哪些方法配置事务-->
<!--新东西:配置事务的传播特性 propagation-->
<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"/>
<!-- *号包含上面4个方法:
<tx:method name="*" propagation="REQUIRED"/> -->
</tx:attributes>
</tx:advice>

<!--配置事务切入-->
<aop:config>
<aop:pointcut id="txpointcut" expression="execution(* mapper.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txpointcut"/>
</aop:config>

</beans>

applicationContext.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?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="mapper.UserMapperImpl">
<property name="sqlSessionFactory" ref="sqlSessionFactory"></property>
</bean>
</beans>

评论