狂神Spring教学视频学习笔记,包括IOC、依赖注入、自动装配、代理模式、AOP、整合Mybatiis等内容
Spring 0 写在前面 注解说明 @Autowired注解:自动装配
默认通过byType的方式实现,如果相同Type>1,就用byName,而且必须要求这个对象存在【常用】
如果不能唯一自动装备属性,用@Qualifier(value = "xxx")
配合使用,指定一个唯一的bean注入使用。
@Resource 注解:自动装配
默认通过byname的方式实现,如果找不到名字,则通过byType实现!如果两个都找不到的情况下,就报错。
@Resource(name = “xx”) 或者 @Resource
设置作用域的注解:
几种声明实体类被Spring管理成为bean对象的注解:
@Component //pojo层
@Service //dao层
@Service //service层
@Controller //contriller层
重点 4 5 6,后面springboot全注解开发,动态代理、AOP
1、Spring简介 1.1 Spring概述 Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器(框架)。 如下优点:
Spring是一个开源免费的框架 , 容器 .
Spring是一个轻量级的框架 , 非侵入式的 .
控制反转 IoC , 面向切面 Aop
对事物的支持 , 对框架的支持
1.2 Spring的组成 Spring 框架是一个分层架构,由 7 个定义良好的模块组成。Spring 模块构建在核心容器之上,核心容器 定义了创建、配置和管理 bean 的方式 :
组成 Spring 框架的每个模块(或组件)都可以单独存在,或者与其他一个或多个模块联合实现。每个模 块的功能如下:
*核心容器(Spring Core)**:核心容器提供 Spring 框架的基本功能。核心容器的主要组件是 BeanFactory,它是工厂模式的实现。BeanFactory 使用 控制反转 (IOC) 模式将应用程序的配置和依赖性规范与实际的应用程序代码分开*。
*Spring 上下文(Spring Context)**:Spring 上下文是一个 配置文件*,向 Spring 框架提供上下文信息。Spring 上下文包括企业服务、EJB(企业Java Bean)、电子邮件、国际化、校验和调度功能。
Spring AOP:通过配置管理特性,Spring AOP 模块直接将面向切面的编程功能集成到了 Spring 框架中。所以,可以很容易地使 Spring 框架管理的任何对象支持 AOP。Spring AOP 模块为基于 Spring 的应用程序中的对象提供了事务管理服务。
Spring DAO:JDBC DAO 抽象层提供了有意义的异常层次结构,可用该结构来管理异常处理和不同数据库供应商抛出的错误消息。异常层次结构简化了错误处理,并且极大地降低了需要编写 的异常代码数量(例如打开和关闭连接)。Spring DAO 的面向 JDBC 的异常遵从通用的 DAO 异常层次结构。
Spring ORM:Spring 框架插入了若干个 ORM 框架(对象关系映射),从而提供了 ORM 的对象关系工具,其中包括 JDO、Hibernate 和 iBatis SQL Map。
Spring Web 模块:Web 上下文模块 建立在应用程序上下文模块之上,为基于 Web 的应用程序提供了上下文。Web 模块还简化了处理多部分请求以及将请求参数绑定到域对象的工作。
Spring MVC 框架:MVC 框架是一个全功能的构建 Web 应用程序的 MVC 实现。通过策略接口,MVC 框架变成为高度可配置的,MVC 容纳了大量视图技术,其中包括 JSP。
1.3 Spring的配置和官方文档 配置:
1 2 3 4 5 6 7 8 9 10 11 12 <dependency > <groupId > org.springframework</groupId > <artifactId > spring-webmvc</artifactId > <version > 5.2.0.RELEASE</version > </dependency > <dependency > <groupId > org.springframework</groupId > <artifactId > spring-JDBC</artifactId > <version > 5.2.0.RELEASE</version > </dependency >
官方文档:
官网 : http://spring.io/
官方下载地址 : https://repo.spring.io/libs-release-local/org/springframework/spring/
GitHub : https://github.com/spring-projects
几个重点的内容:IOC的原理和创建对象方式、依赖注入、代理模式、AOP、整合Mybatis
以前学的javaWeb又不懂了、Dao接口、实现类、Service接口、实现类、myTest主程序….
2、IOC 控制翻转 2.1 将对象的创建交给程序而不是程序员 JavaWeb应用的MVC的三层架构如下图所示,控制层Controller调用模型层的一个Service业务,再由然后业务层调用dao层,获取数据。
由Service层决定对象的创建
先写一个UserDao接口
1 2 3 public interface UserDao { void getUser () ; }
再去写Dao的实现类(这里有三个具体的实现类)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public class UserDaoImpl implements UserDao { public void getUser () { System.out.println("默认获取用户的数据!!!" ); } } public class UserDaoMysqlImpl implements UserDao { public void getUser () { System.out.println("Mysql 获取用户数据 !!!" ); } } public class UserDaoOracleImpl implements UserDao { public void getUser () { System.out.println("Oracle 获取用户数据!!!" ); } }
然后去写UserService的接口
1 2 3 public interface UserService { void getUser () ; }
最后写Service的实现类
1 2 3 4 5 6 7 8 9 10 public class UserServiceImpl implements UserService { private UserDao userDao = new UserDaoImpl(); @Override public void getUser () { userDao.getUser(); } }
测试一下
1 2 3 4 5 6 7 public class MyTest { public static void main (String[] args) { UserServiceImpl userService = new UserServiceImpl(); userService.getUser(); } }
如上,因为Service层的实现类 调用Dao层创建的对象的实现是new UserDaoImpl();
,所以将打印实现类1的输出语句:
如果此时换了一种Dao层的实现类 ,比如用实现类2或实现类3,就必须修改Service层的实现类 中创建对象的方法UserDao userDao = new UserDaoMysqlImpl();
,相应得到的输出语句为:
每一次业务需求发生变化、都需要程序员修改创建对象的代码,如果这个对象使用了很多次,那么每个地方都要修改,可维护性很差。
在测试类中决定对象的创建 修改Service实现类的代码,只写一个传递userDao类的set方法,而不具体的创建userDao对象
增加一个set方法,用来传递到底要实现哪个具体的dao层实现类
1 2 3 4 5 6 7 8 9 10 11 12 13 public class UserServiceImpl2 implements UserService { private UserDao userDao; private void setUserDao (UserDao userDao) { this .userDao = userDao; } @Override public void getUser () { userDao.getUser(); } }
重新写一个测试方法
1 2 3 4 5 6 7 8 public class MyTest2 { public static void main (String[] args) { UserServiceImpl2 userService = new UserServiceImpl2(); userService.setUserDao(new UserDaoImpl()); userService.getUser(); } }
我的理解是:将本来要在service层决定创建哪个dao实现类对象的new UserDaoImpl();
语句,搬到了测试方法中,在测试方法中你想用哪个实现类,你就new哪个实现类就好了,不必因为需求的变化而修改Service的实现类。
现在控制对象创建的是用户(测试类需要什么就是用户需求),而之前控制对象创建的是Service层(也就是程序员负责的代码。小狂神说这就是IOC的原型, 让程序员不再去管理对象的创建了 , 更多的去关注业务的实现。
2.2 IOC本质 控制反转IoC(Inversion of Control),是一种设计思想,DI(依赖注入)是实现IOC的一种方法 。没有IoC的程序中 , 我们使用面向对象编程 , 对象的创建与对象间的依赖关系 完全硬编码在程序中,对象的创建由程序自己控制,控制反转后将对象的创建转移给第三方.
控制反转是一种通过描述(XML或注解)并通过第三方去生产或获取特定对象的方式 。在Spring中实现控制反转的是IoC容器 ,其实现方法是依赖注入 (Dependency Injection,DI)。
采用XML方式配置Bean的时候,Bean的定义信息是和实现分离的,而采用注解的方式可以把两者合为 一体,Bean的定义信息直接以注解的形式定义在实现类中,从而达到了零配置的目的。
2.3 第一个Spring程序 IOC控制反转说白了就是将对象的创建和管理交给”别人“ 而不是对象本身,这个别人是谁呢?就是Spring,,使用Spring来创建的对象,都称为Bean
新建一个maven子项目,在Java下新建com.kuang.pojo包和Hello实体类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 package com.kuang.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 "Hello{" + "str='" + str + '\'' + '}' ; } }
这里采用xml配置文件的方式编写我们的spring文件 , 这里命名为beans.xml
创建对象的语句变成了一对<bean> </bean>
的标签
1 2 3 <bean id ="hello_1" class ="com.kuang.pojo.Hello" > <property name ="str" value ="setTheValueOfhello_1" /> </bean >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 <?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 http://www.springframework.org/schema/beans/spring-beans.xsd" > <bean id ="hello_1" class ="com.kuang.pojo.Hello" > <property name ="str" value ="setTheValueOfhello_1" /> </bean > </beans >
我们可以去进行测试了 .
1 2 3 4 5 6 7 8 9 public class MyTest { public static void main (String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml" ); Hello hello = (Hello) context.getBean("hello_1" ); System.out.println(hello.toString()); } }
思考
这个过程就叫控制反转 :
控制 : 谁来控制对象的创建 , 传统应用程序的对象是由程序本身控制创建的 , 使用Spring后 , 对象是 由Spring来创建的
反转 : 程序本身不创建对象 , 而变成被动的接收对象 .
依赖注入 : 就是利用set方法来进行注入的.
IOC是一种编程思想,由主动的编程变成被动的接收
可以通过newClassPathXmlApplicationContext去浏览一下底层源码 :
2.4 用Spring的方式改写第一个UserDao的例子 步骤同样是如下:
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 <?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 http://www.springframework.org/schema/beans/spring-beans.xsd" > <bean id ="userDaoImpl_wk" class ="com.kuang.dao.UserDaoImpl" /> <bean id ="userDaoMysqlImpl_wk" class ="com.kuang.dao.UserDaoMysqlImpl" /> <bean id ="userDaoOracleImpl_wk" class ="com.kuang.dao.UserDaoOracleImpl" /> <bean id ="ServiceImpl_wk" class ="com.kuang.service.UserServiceImpl2" > <property name ="userDao" ref ="userDaoImpl_wk" /> </bean > <bean id ="ServiceMysqlImpl_wk" class ="com.kuang.service.UserServiceImpl2" > <property name ="userDao" ref ="userDaoMysqlImpl_wk" /> </bean > <bean id ="ServiceOracleImpl_wk" class ="com.kuang.service.UserServiceImpl2" > <property name ="userDao" ref ="userDaoOracleImpl_wk" /> </bean > </beans >
写测试类,想调哪个直接再getBean()
方法的参数中输入再bean.xml中的参数id就好了
1 2 3 4 5 6 7 8 9 10 11 public class MyTest { public static void main (String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml" ); UserServiceImpl2 userServiceImpl = (UserServiceImpl2) context.getBean("ServiceMysqlImpl_wk" ); userServiceImpl.getUser(); } }
OK , 到了现在 , 我们彻底不用再程序中去改动了 , 要实现不同的操作 , 只需要在xml配置文件中进行修改 , 所谓的IoC,一句话搞定 : 对象由Spring 来创建 , 管理 , 装配 !
2.5 IOC 创建对象的三种方式 实体类中,含有构造函数时,beans.xml 有三种方式编写来创建对象
实体类:
1 2 3 4 5 6 7 8 public class User { private String name; public User (String name) { this .name = name; } }
方式一:直接通过参数名(与类中的参数保持一致)来设置,多个参数写多个constructor
1 2 3 4 <bean id ="user" class ="com.kuang.pojo.User" > <constructor-arg name ="name" value ="秦疆1" /> </bean >
方式二:根据index参数下标设置
1 2 3 4 5 <bean id ="user" class ="com.kuang.pojo.User" > <constructor-arg index ="0" value ="kuangshen2" /> </bean >
方式三:根据参数类型设置
1 2 3 4 <bean id ="user" class ="com.kuang.pojo.User" > <constructor-arg type ="java.lang.String" value ="kuangshen3" /> </bean >
结论:在配置文件加载的时候。其中管理的对象都已经初始化了!
2.6 Spring 配置 1. 别名 alias 1 2 3 4 <alias name ="user" alias ="userNew" /> //User user = (User) context.getBean("userNew");
2. bean的配置 1 2 3 4 5 6 7 8 9 10 <bean id ="user" class ="edu.cqupt.pojo.User" name ="user2,u2,u3,u4" > <constructor-arg name ="name" value ="shilin" /> </bean > //User user = (User) context.getBean("user2");
3. import import,一般用于团队开发使用,他可以将多个配置文件,导入合并为一个
1 2 3 <import resource ="beans.xml" /> <import resource ="beans2.xml" /> <import resource ="beans3.xml" />
3、依赖注入
依赖注入:通俗来讲就是对象的创建和初始化(赋值)
依赖:bean对象的创建依赖于容器!
注入:bean对象的所有属性,有容器来注入!
3.1 构造器注入 2.5节已经说了有参构造方法创建对象的三种方式 constructor-arg
3.2 Set方式注入【重点】 环境搭建
复杂类型 Addresss
真实测试对象 Student
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public class Student { private String name; private Addresss addresss; private String[] books; private List<String> hobbies; private Map<String,String> card; private Set<String> games; private String wife; private Properties info; ...gets/sets } public class Addresss { private String address; ...gets/sets }
1、常量注入 value
1 2 3 4 <bean id ="student" class ="com.kuang.pojo.Student" > <property name ="name" value ="法外狂徒张三" /> </bean >
2、Bean注入: ref 注入bean中已经创建好的对象:addr
1 2 3 4 5 6 <bean id ="addr" class ="com.kuang.pojo.Address" > <property name ="address" value ="长沙" /> </bean > <property name ="address" ref ="addr" />
3、数组注入: array
1 2 3 4 5 6 7 8 <property name ="books" > <array > <value > Java 程序设计</value > <value > Python 从入门到精通</value > <value > MYSQL 必知必会</value > </array > </property >
4、List 注入
1 2 3 4 5 6 7 8 <property name ="hobbies" > <list > <value > 编程</value > <value > 听音乐</value > <value > 看电影</value > </list > </property >
5、Map 注入
1 2 3 4 5 6 7 8 <property name ="card" > <map > <entry key ="学生卡" value ="1234567" /> <entry key ="身份证" value ="123453232367" /> <entry key ="银行卡" value ="3332434343434343" /> </map > </property >
6、Set 注入
1 2 3 4 5 6 7 8 <property name ="games" > <set > <value > LOL</value > <value > 王者荣耀</value > <value > BOB</value > </set > </property >
7、Null 注入
1 2 3 4 <property name ="wife" > <null /> </property >
8、properties 注入
1 2 3 4 5 6 7 8 9 <property name ="info" > <props > <prop key ="driver" > com.mysql.jdbc.Driver</prop > <prop key ="url" > jdbc:mysql://localhost:3306/mydb</prop > <prop key ="username" > root</prop > <prop key ="password" > 123456</prop > </props > </property >
测试一下
1 2 3 4 5 6 7 public class Test01 { public static void main (String[] args) { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beans.xml" ); Student student1 = (Student) context.getBean("student_1" ); System.out.println(student1.toString()); } }
3.3 拓展方式注入 先不看了….
3.4 Bean 的作用域 bean 的作用域分类
singleton : 唯一 bean 实例,Spring 中的 bean 默认都是单例的。
prototype : 每次请求都会创建一个新的 bean 实例。
request : 每一次HTTP请求都会产生一个新的bean,该bean仅在当前HTTP request内有效。
session : 每一次HTTP请求都会产生一个新的 bean,该bean仅在当前 HTTP session 内有效。
global-session: 全局session作用域,仅仅在基于portlet的web应用中才有意义,Spring5已经没有了。Portlet是能够生成语义代码(例如:HTML)片段的小型Java Web插件。它们基于portlet容器,可以像servlet一
singleton (默认–单例模式) 只有一个单例 bean 的共享实例被管理,并且所有对带有一个或多个 ID 与该 bean 定义匹配的 bean 的请求都会导致 Spring 容器返回一个特定的 bean 实例。
测试一下,发现getBean("user1")
永远创建的是用一个对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public class Test01 { public static void main (String[] args) { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beans.xml" ); User user1 = (User) context.getBean("user1" ); User user2 = (User) context.getBean("user1" ); System.out.println(user1.toString()); System.out.println(user2.toString()); System.out.println(user1.hashCode()); System.out.println(user2.hashCode()); System.out.println(user1==user2); } }
prototypeton (原型模式) 每次从容器中get的时候,都会产生一个对象
首先在配置文件的<bean>
标签中,设置scope="prototype"
1 2 3 4 <bean id ="user1" class ="com.kuang.pojo.User " scope ="prototype" > <property name ="name" value ="wukang" /> <property name ="age" value ="18" /> </bean >
测试一下,发现getBean("user1")
创建的是不同的对象
4、自动装备和使用注解开发 4.1 Bean 的自动装配 在Spring中有三种装配的方式:
在xml中显式的装配(上面都是用的这种实现)
在java中显式的配置
隐式的自动装配bean (很重要):在配置文件的<bean>
标签中,设置autowire=""
属性
1 Bean 自动装配的示例 Bean 的自动装配指Spring会在上下文中自动寻找,并自动给bean装备属性。 ,用大白话来说就是:原本给一个复杂的对象赋值属性的时候,如果要调用已经存在的对象的话需要每个都写一个<property>
标签来赋值。。如果采用自动装备的话则可以省略这些已有对象的调用。对比如下:
1、自己创建一个复杂对象:
1 2 3 4 5 6 7 8 9 <bean id ="dog" class ="com.kuang.pojo.dog" > <bean id ="cat" class ="com.kuang.pojo.cat" > <bean id ="people" class ="com.kuang.pojo.People" > <property name ="name" value ="shi-lin" /> <property name ="cat" ref ="cat" /> <property name ="dog" ref ="dog" /> </bean >
2、自动装备创建一个复杂对象1(这里采用autowire="byName"
的方式):
1 2 3 4 5 6 7 <bean id ="dog" class ="com.kuang.pojo.dog" > <bean id ="cat" class ="com.kuang.pojo.cat" > <bean id ="people" class ="com.kuang.pojo.People" autowire ="byName" > <property name ="name" value ="shi-lin" /> </bean >
3、自动装备创建一个复杂对象2(这里采用autowire="byType"
的方式):
1 2 3 4 5 6 7 <bean id ="dog1" class ="com.kuang.pojo.dog" > <bean id ="cat1" class ="com.kuang.pojo.cat" > <bean id ="people" class ="edu.cqupt.pojo.People" autowire ="byType" > <property name ="name" value ="shi-lin" /> </bean >
2 ByName 和 ByType 的区别:
byNmae 会自动在容器上下文中查找和自己对象set方法后面的值对应的id
byName需要保证所有bean的id唯一,并且这个bean需要和自动注入的属性的set方法的值唯一
byType 会自动在容器上下文中查找和自己对象属性类型相同的bean
byType的时候,需要保证所有bean的class唯一,并且这个bean需要和自动注入的属性的类型一致
3 注解实现自动装配 xml配置文件需要引入支持注解
导入约束。 contex约束 xmlns:context="http://www.springframework.org/schema/context"
配置注解的支持 <context:annotation-config/>
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和@Resource **
@Autowired注解:自动装配
默认通过byType的方式实现,如果相同Type>1,就用byName,而且必须要求这个对象存在【常用】
如果不能唯一自动装备属性,用@Qualifier(value = "xxx")
配合使用,指定一个唯一的bean注入使用。
@Resource 注解:自动装配
默认通过byname的方式实现,如果找不到名字,则通过byType实现!如果两个都找不到的情况下,就报错。
@Resource(name = “xx”) 或者 @Resource
自动装配注解使用示例:直接在属性上加上注解即可
1 2 3 4 5 6 7 8 9 10 public class People { @Autowired @Qualifier(value = "cat1") private Cat cat; @Autowired @Qualifier(value = "dog1") private Dog dog; private String name; }
使用注解后自动装配,配置文件的代码将极度简洁
1 2 3 4 5 <bean id ="cat1" class ="com.kuang.pojo.Cat" /> <bean id ="cat2" class ="com.kuang.pojo.Cat" /> <bean id ="dog1" class ="com.kuang.pojo.Dog" /> <bean id ="dog2" class ="com.kuang.pojo.Dog" /> <bean id ="people" class ="com.kuang.pojo.People" />
4.2 使用注解开发 1 一个使用注解开发的简单实例
引入注解的支持,在xml配置文件中导入contex约束,并配置注解的支持(注意使用注解还需要导入aop的依赖包)
1 2 3 4 5 6 7 8 9 10 11 12 13 <?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 https://www.springframework.org/schema/context/spring-context.xsd" > <context:component-scan base-package ="com.kuang" /> <context:annotation-config /> </beans >
以@Component和@Value()注解为例,声明实体类被Spring管理,成为了一个bean
a. 普通情况,不用注解、使用xml的配置来创建和管理对象
1 2 3 4 5 6 public class User { String name; public void setName (String name) { this .name = name; } }
1 2 3 4 <bean name ="user1" class ="com.kuang.pojo.User" > <property name ="name" value ="wukang" /> </bean >
b. 使用注解的情况,在实体类的属性上加注解、然后xml配置文件将极其简洁(就是直接不用写<bean>
以及里面的内容了)
1 2 3 4 5 6 7 8 @Component public class User { @Value("wukang") String name; public void setName (String name) { this .name = name; } }
c. 解释:
@Component : 组件等价于: <bean id="user" class="com.kuang.pojo.User"/>
@Value(“wukang”) 等价于:<property name="name" value="wukang"/>
2 介绍几种注解【重要】 几种声明实体类被Spring管理成为bean对象的注解:
1 2 3 4 @Component @Repository @Service @Controller
作用域的注解:
singleton:默认的,Spring会采用单例模式创建这个对象。关闭工厂 ,所有的对象都会销毁。 prototype:多例模式。关闭工厂 ,所有的对象不会销毁。内部的垃圾回收机制会回收
1 2 @Scope("singleton") @Scope("prototype")
自动装配的注解
1 2 3 4 5 6 7 @Autowired注解:自动装配【常用】 - 默认通过byType的方式实现,如果相同Type>1,就用byName,而且必须要求这个对象存在 - 如果不能唯一自动装备属性,用`@Qualifier(value = "xxx")`配合使用,指定一个唯一的bean注入使用。 @Resource 注解:自动装配 - 默认通过byname的方式实现,如果找不到名字,则通过byType实现!如果两个都找不到的情况下,就报错。 - @Resource(name = "xx") 或者 @Resource
3 使用注解开发的小结
xml配置 与 注解 两种方式的特点:
xml :更加万能,适用于任何场合、维护简单方便
注解 : 不是自己的类,使用不了,维护相对复杂
两种方式的最佳实践
4.3 JavaConfig实现配置 事实上也可以直接不用建bean.xml的配置文件,用一些纯java的类完全代替之….【现阶段了解、springboot中用的会比较多】
1 首先给实体类加上注解,使用注解开发的形式
1 2 3 4 5 6 7 8 9 10 11 @Component public class User { private String name; public String getName () { return name; } @Value("wukang") public void setName (String name) { this .name = name; } }
2 写一个java类,带上@Configuration
表明是配置类,然后类中的每一个方法加上@Bean
注解,表明是一条bean的配置语句
1 2 3 4 5 6 7 8 9 10 @Configuration public class Config1 { @Bean public User user1 () { return new User(); } }
3、写测试类,用AnnotationConfigApplicationContext
来new一个ApplicationContext
对象
1 2 3 4 5 6 7 public class MyTest01 { public static void main (String[] args) { ApplicationContext context = new AnnotationConfigApplicationContext(Config1.class); User userWuKang = (User) context.getBean("user1" ); System.out.println(userWuKang.getName()); } }
这里再介绍几个配套的注解
@ComponentScan(“com.kuang.pojo”) //扫描类,加上之后可以直接点击跳转
@Import(Config2.class) //可以整合多个配置类的java文件,,相当于合并多个bean.xml文件一样
5、代理模式 5.1 静态代理 我觉得讲的我听不太懂、简单做亿点笔记,后面自己去看书。
几个组成部分(以出租房子为例)
抽象角色: 一般会使用一个接口或者抽象类来实现(比如出租房子这件事)
真实角色:被代理的角色(这里指房东实现出租房子的接口)
代理角色:代理真实角色,代理真实角色后,一般会做一些附属操作(这里指中介、帮房东出租房子,也要实现出租房子的接口、但有自己的一些其他方法)
客户:访问代理对象的人 (这里表示要租房子的人)
静态代理模式的好处:
静态代理模式的缺点:
一个真实角色就会产生一个代理角色,代码量会翻倍,开发效率会变低。
以一个AOP插入log功能的示例演示一下:
1 2 3 4 5 6 public interface UserService { public void add () ; public void delete () ; public void update () ; public void query () ; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public class UserServiceImpl implements UserService { public void add () { System.out.println("增加了一个用户" ); } public void delete () { System.out.println("删除了一个用户" ); } public void update () { System.out.println("修改了一个用户" ); } public void query () { System.out.println("查询了一个用户" ); } }
**UserServiceProxy ** 代理角色
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 public class UserServiceProxy implements UserService { private UserServiceImpl userService; public void setUserService (UserServiceImpl userService) { this .userService = userService; } public void add () { log("add" ); userService.add(); } public void delete () { log("delete" ); userService.delete(); } public void update () { log("update" ); userService.update(); } public void query () { log("query" ); userService.query(); } public void log (String msg) { System.out.println("[DEBUG]:使用了" + msg + "方法." ); } }
1 2 3 4 5 6 7 8 public class Client { public static void main (String[] args) { UserServiceImpl userService = new UserServiceImpl(); UserServiceProxy proxy = new UserServiceProxy(); proxy.setUserService(userService ); proxy.delete(); } }
5.2 动态代理 ==最大的区别:动态代理的代理类是动态生成的,不是我们直接写好的 (具体是怎样?) ==
需要了解两个类【重要!!】
Proxy: new出代理
InvocationHandler: 调用处理程序生成代理
还是以为业务层增加log日志提示的例子为例,代码如下:
1首先编写我们的业务接口和实现类和之前一样。
2 之前使用静态代理就要 “写死” 一个代理类UserServiceProxy **,里面的方法固定、增加的功能无法改变。 使用动态代理的话、不必程序员写这个代理类了、而是自动生成代理类!!**
3最后测试:**Client **客户请求服务、代理对象提供服务
UserService 抽象角色:还是一样一个接口,里面四个方法
UserServiceImpl 真实角色:还是一样,实现四个方法
一个用来自动生成代理类的ProxhyInvocationHandler 类、下面这个通用、基本算是工具类
里面的getProxy()、invoke()方法基本都是写死的,
如果要代理多个方法用Object对象,如果只有一个方法就用对于的接口类就好了
添加的新功能直接写成实例方法、然后在invoke()方法里面调用
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 import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;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 { log(method.getName()); Object result = method.invoke(target,args); return result; } public void log (String msg) { System.out.println("[Debug]:执行了" + msg + "方法。" ); } }
**Client **客户请求服务、代理对象提供服务
最关键的就是这个自动生成代理类对象、然后就可以调用真实被代理对象的方法了
UserService proxy = (UserService) pih.getProxy(); // 动态生成代理类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 package edu.cqupt.demo04;public class Client { public static void main (String[] args) { UserServiceImpl userService = new UserServiceImpl(); UserServiceImplTwo userServiceTwo = new UserServiceImplTwo(); ProxyInVocationHandler pih = new ProxyInVocationHandler(); pih.setTarget(userService); UserService proxy = (UserService) pih.getProxy(); proxy.add(); proxy.delete(); proxy.update(); proxy.query(); } }
6、AOP AOP为Aspect Oriented Programming的缩写,意为:面向切面编程 ,通过预编译方式和运行期间动态代理 实现程序功能的统一维护的一种技术。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
AOP 在Spring中的作用 提供声明式事务:允许用户自定义切面:
横切关注点: 跨越应用程序多个模块的方法或功能.既是,与我们业务逻辑无关,但是我们需要关注的部分,就是横切关注点 .如日志,安全,缓存,事务 等…
切面(ASPECT): 横切关注点 被模块化 的特殊对象。即,它是一个类 。
通知(Advice): 切面必须要完成的工作。即,它
是类中的一个方法 。
目标(Target): 被通知对象。
代理(Proxy): 向目标对象应用通知之后创建的对象。
切入点(PointCut): 切面通知 执行的 “地点”的定义。
连接点(JointPoint): 与切入点匹配的执行点。
SpringAOP中,通过Advice定义横切逻辑,Spring中支持5种类型的Advice:
使用Spring 实现AOP Aop 在 不改变原有代码的情况下 , 去增加新的功能。其实动态代理就可以实现AOP不改变代码增加新功能的需求、、但是Spring内部定义了一下三种实现AOP的三种方式
方式一: 使用Spring的API接口
方式二: 使用自定义类实现AOP
方式三: 使用注解实现
使用Spring实现AOP织入,需要导入一个依赖包!
1 2 3 4 5 <dependency > <groupId > org.aspectj</groupId > <artifactId > aspectjweaver</artifactId > <version > 1.9.4</version > </dependency >
1 使用API接口实现AOP
1 首先编写我们的业务接口和实现类和之前一样。
2 添加新的功能,两个增强类,一个前置增强类Log实现MethodBeforeAdvice接口,一个后置增强类AfterLog实现AfterReturningAdvice接口
3 最后去spring的文件中注册 , 并实现aop切入实现 , 注意导入约束 .
4 测试
UserService 抽象角色
UserServiceImpl 真实角色
前置增强类Log实现MethodBeforeAdvice接口,重写before方法、添加新功能
1 2 3 4 5 6 7 8 9 public class Log implements MethodBeforeAdvice { @Override public void before (Method method, Object[] objects, Object o) throws Throwable { System.out.println( o.getClass().getName() + "的" + method.getName() + "方法被执行了" ); } }
后置增强类AfterLog实现AfterReturningAdvice接口,重写afterReturning方法、添加新功能
1 2 3 4 5 6 7 8 9 10 11 public class AfterLog implements AfterReturningAdvice { @Override public void afterReturning (Object returnValue, Method method, Object[] args, Object target) throws Throwable { System.out.println("执行了" + target.getClass().getName() +"的" +method.getName()+"方法," +"返回值:" +returnValue); } }
spring的xml文件中注册 , 并实现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 <?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 https://www.springframework.org/schema/context/spring-context.xsd" > <bean id ="userService" class ="com.kuang.service.UserServiceImpl" /> <bean id ="log" class ="com.kuang.log.Log" /> <bean id ="afterLog" class ="com.kuang.log.AfterLog" /> <aop:config > <aop:pointcut id ="pointcut" expression ="execution(*com.kuang.service.UserServiceImpl.*(..))" /> <aop:advisor advice-ref ="log" pointcut-ref ="pointcut" /> <aop:advisor advice-ref ="afterLog" pointcut-ref ="pointcut" /> </aop:config > </beans >
1 2 3 4 5 6 7 public class MyTest { @Test public void test () { ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml" ); UserService userService = (UserService)context.getBean("userService" ); userService.search(); } }
Aop的重要性 : 很重要 . 一定要理解其中的思路 , 主要是思想的理解这一块 .
Spring的Aop就是将公共的业务 (日志 , 安全等) 和领域业务结合起来 , 当执行领域业务时 , 将会把公共业 务加进来 . 实现公共业务的重复利用 . 领域业务更纯粹 , 程序猿专注领域业务 , 其本质还是动态代理 .
2 使用自定义类实现AOP
1 首先编写我们的业务接口和实现类和之前一样。
2 写我们自己定义的一个切入类,要新增的功能在方法里编写
3 最后去spring的文件中配置, 并实现aop切入实现 , 注意导入约束 .
4 测试
UserService 抽象角色
UserServiceImpl 真实角色
写我们自己定义的一个切入类
1 2 3 4 5 6 7 8 public class DiyPointcut { public void before () { System.out.println("---------方法执行前---------" ); } public void after () { System.out.println("---------方法执行后---------" ); } }
最后去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 <?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 https://www.springframework.org/schema/context/spring-context.xsd" > <bean id ="diy" class ="com.kuang.config.DiyPointcut" /> <aop:config > <aop:aspect ref ="diy" > <aop:pointcut id ="diyPonitcut" expression ="execution(*com.kuang.service.UserServiceImpl.*(..))" /> <aop:before pointcut-ref ="diyPonitcut" method ="before" /> <aop:after pointcut-ref ="diyPonitcut" method ="after" /> </aop:aspect > </aop:config > </beans >
1 2 3 4 5 6 7 public class MyTest { @Test public void test () { ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml" ); UserService userService = (UserService) context.getBean("userService" ); userService.add(); } }
3 使用注解实现AOP
1 首先编写我们的业务接口和实现类和之前一样。
2 编写一个注解实现的增强类
3 在Spring配置文件中,注册bean,并增加支持注解的配置
4 测试
UserService 抽象角色
UserServiceImpl 真实角色
编写一个注解实现的增强类
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 package com.kuang.diy;import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.Signature;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 AnnotationPointCut { @Before("execution(* com.kuang.service.UserServiceImpl.*(..))") public void before () { System.out.println("=====方法执行前======" ); } @After("execution(* com.kuang.service.UserServiceImpl.*(..))") public void after () { System.out.println("=====方法执行后======" ); } @Around("execution(* com.kuang.service.UserServiceImpl.*(..))") public void around (ProceedingJoinPoint jp) throws Throwable { System.out.println("环绕前" ); Signature signature = jp.getSignature(); System.out.println("signature:" +signature); Object proceed = jp.proceed(); System.out.println("环绕后" ); System.out.println(proceed); } }
在Spring配置文件中,注册bean,并增加支持注解的配置
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 ="com.kuang.service.UserServiceImpl" /> <bean id ="annotationPointCut" class ="com.kuang.diy.AnnotationPointCut" /> <aop:aspectj-autoproxy /> </beans >
7 整合 Mybatis 整合Mybatis的步骤:
1 2 3 4 5 6 junit mybatis mysql数据库 spring aspectjweaver mybatis-spring
7.1 回顾Mybatis
1 建表、导入依赖包:
2 resources下建一个mybaits-config.xml文件,Mybatis配置文件用于连接数据库
3 pojo包下写User实体类,Dao包下写一个Dao接口
4 接口实现类由原来的UserDaoImpl转变为一个 Mapper.xml配置文件
5 测试 //获得sqlSession对象 //调用配置文件,查询sql
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 <dependencies > <dependency > <groupId > org.springframework</groupId > <artifactId > spring-webmvc</artifactId > <version > 5.2.8.RELEASE</version > </dependency > <dependency > <groupId > junit</groupId > <artifactId > junit</artifactId > <version > 4.12</version > </dependency > <dependency > <groupId > org.aspectj</groupId > <artifactId > aspectjweaver</artifactId > <version > 1.9.4</version > </dependency > <dependency > <groupId > mysql</groupId > <artifactId > mysql-connector-java</artifactId > <version > 5.1.47</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.1.9.RELEASE</version > </dependency > <dependency > <groupId > org.mybatis</groupId > <artifactId > mybatis-spring</artifactId > <version > 2.0.2</version > </dependency > <dependency > <groupId > org.projectlombok</groupId > <artifactId > lombok</artifactId > <version > 1.18.4</version > </dependency > </dependencies > <build > <resources > <resource > <directory > src/main/java</directory > <includes > <include > **/*.xml</include > </includes > <filtering > true</filtering > </resource > </resources > </build >
resources下建一个mybatis-config.xml文件、注意注册mapper.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 <?xml version="1.0" encoding="UTF8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd" > <configuration > <environments default ="development" > <environment id ="development" > <transactionManager type ="JDBC" /> <dataSource type ="POOLED" > <property name ="driver" value ="com.mysql.jdbc.Driver" /> <property name ="url" value ="jdbc:mysql://localhost:3306/mybatis?useSSL=true& useUnicode=true& characterEncoding=UTF-8" /> <property name ="username" value ="root" /> <property name ="password" value ="526736" /> </dataSource > </environment > </environments > <mappers > <mapper resource ="com/kuang/dao/Mapper.xml" /> </mappers > </configuration >
pojo包下写User实体类,Dao包下写一个Dao接口
1 2 3 4 5 6 7 8 9 import lombok.Data;@Data public class User { private int id; private String name; private String pwd; }
1 2 3 4 5 6 import com.kuang.pojo.User;import java.util.List;public interface UserDao { List<User> getUserList () ; }
一个 Mapper.xml配置文件实现UserDao接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 <?xml version="1.0" encoding="UTF8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > <mapper namespace ="com.kuang.dao.UserDao" > <select id ="getUserList" resultType ="com.kuang.pojo.User" > select * from mybatis.user </select > </mapper >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public class MyTest01 { @Test public void test () throws IOException { String resource = "mybatis-config.xml" ; InputStream in = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(in); SqlSession sqlSession = sqlSessionFactory.openSession(true ); UserDao mapper = sqlSession.getMapper(UserDao.class); List<User> userList = mapper.getUserList(); for (User user : userList) { System.out.println(user); } } }
7.2 整合实现方式一 MyBatis-Spring 会帮助你将 MyBatis 代码无缝地整合到 Spring 中。整合需要导的包
1 2 3 4 5 <dependency > <groupId > org.mybatis</groupId > <artifactId > mybatis-spring</artifactId > <version > 2.0.2</version > </dependency >
要和 Spring 一起使用 MyBatis,需要在 Spring 应用上下文中定义至少两样东西:一个 SqlSessionFactory 和至少一个数据映射器类。 在 MyBatis-Spring 中,可使用 SqlSessionFactoryBean 来创建 SqlSessionFactory 。 要配置 这个工厂 bean,只需要把下面代码放在 Spring 的 XML 配置文件中:
1 2 3 <bean id ="sqlSessionFactory" class ="org.mybatis.spring.SqlSessionFactoryBean" > <property name ="dataSource" ref ="dataSource" /> </bean >
SqlSessionTemplate 是 MyBatis-Spring 的核心。作为 SqlSession 的一个实现,这意味着可 以使用它无缝代替你代码中已经在使用的 SqlSession 。可以使用 SqlSessionFactory 作为构造方法的参数来创建 SqlSessionTemplate 对象。
1 2 3 <bean id ="sqlSession" class ="org.mybatis.spring.SqlSessionTemplate" > <constructor-arg index ="0" ref ="sqlSessionFactory" /> </bean >
当拥有sqlSession对象之后,就可以为所欲为了 。使用方法是实现抽象接口,在实现类中添加一个 SqlSession 属性,并写一个set()方法,方便注入。就像下面这样:
1 2 3 4 5 6 7 8 9 10 11 public class UserDaoImpl implements UserDao { private SqlSession sqlSession; public void setSqlSession (SqlSession sqlSession) { this .sqlSession = sqlSession; } public User getUser (String userId) { return sqlSession.getMapper...; } }
最后将你的实现类注入真正的Spring配置文件中就可以正常使用了
第一种整合方式的步骤:
整合的前提是有Mybatis之前的一些文件,比如业务接口UserDao、还有该接口对应用来写SQL的xml文件Mapper.xml、实例类USer、Mybatis的配置文件mybatis-config.xml可有可无(一般保留用来注册别名),在此基础上开始整合:
1 引入Spring配置文件 spring-dao.xml 这个配置文件专门用来,代理原先Mybaits中的一些配置:比如连接数据库、产生SqlSession对象等
a. 配置数据源替换mybaits的数据源
b. 配置SqlSessionFactory,关联MyBatis
c. 注册sqlSessionTemplate,关联sqlSessionFactory;
2 增加Dao接口的实现类;私有化sqlSessionTemplate
a. 用来产生mapper对象,进而调用Dao接口的方法
3 Spring真正的配置文件applicationContext.xml (实际spring-dao.xml和这个xml、分开写好理解)
a. 将上面的spring-dao.xml组合进来
b. 将自己写的实现类,注入到Spring中
4 测试
1 spring-dao.xml配置子文件 : 配置数据源、配置SqlSessionFactory、注册sqlSessionTemplate
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 <?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 http://www.springframework.org/schema/beans/spring-beans.xsd" > <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=true& useUnicode=true& characterEncoding=UTF-8" /> <property name ="username" value ="root" /> <property name ="password" value ="526736" /> </bean > <bean id ="sqlSessionFactory" class ="org.mybatis.spring.SqlSessionFactoryBean" > <property name ="dataSource" ref ="dataSource" /> <property name ="configLocation" value ="classpath:mybatis-config.xml" /> <property name ="mapperLocations" value ="classpath:com/kuang/dao/*.xml" /> </bean > <bean id ="sqlSession" class ="org.mybatis.spring.SqlSessionTemplate" > <constructor-arg index ="0" ref ="sqlSessionFactory" /> </bean > </beans >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public class UserDaoImpl implements UserDao { private SqlSessionTemplate sqlSession; public void setSqlSession (SqlSessionTemplate sqlSession) { this .sqlSession = sqlSession; } @Override public List<User> getUserList () { UserDao mapper = sqlSession.getMapper(UserDao.class); List<User> userList = mapper.getUserList(); return userList; } }
3 Spring真正的配置文件applicationContext.xml 将实现类UserDaoImpl,注入到Spring中
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" xsi:schemaLocation ="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd" > <import resource ="spring-dao.xml" /> <bean id ="userDao" class ="com.kuang.dao.UserDaoImpl" > <property name ="sqlSession" ref ="sqlSession" /> </bean > </beans >
1 2 3 4 5 6 7 8 9 10 11 public class MyText02 { @Test public void text () { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml" ); UserDao userMapper = (UserDao) context.getBean("userDao" ); List<User> userList = userMapper.getUserList(); for (User user:userList){ System.out.println(user); } } }
7.3 整合实现方式二 本质还是第一种整合、方式更加简洁了。
dao继承Support类 , 直接利用 getSqlSession() 获得 , 然后直接注入SqlSessionFactory . 比起方式1 , 不 需要管理SqlSessionTemplate , 而且对事务的支持更加友好 . 可跟踪源码查看
1 重写的类UserDaoImpl修改一下 继承SqlSessionDaoSupport类
2 修改bean的配置
3 测试
1 2 3 4 5 6 7 8 public class UserDaoImpl2 extends SqlSessionDaoSupport implements UserDao { @Override public List<User> getUserList () { UserDao mapper = getSqlSession().getMapper(UserDao.class); List<User> userList = mapper.getUserList(); return userList; } }
Spring真正的配置文件applicationContext.xml
还是要spring-dao.xml文件来帮忙生成sqlSessionFactory对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 <?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 http://www.springframework.org/schema/beans/spring-beans.xsd" > <import resource ="spring-dao.xml" /> <bean id ="userDao2" class ="com.kuang.dao.UserDaoImpl2" > <property name ="sqlSessionFactory" ref ="sqlSessionFactory" /> </bean > </beans >
1 2 3 4 5 6 7 8 9 10 11 public class MyTest03 { @Test public void test () { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml" ); UserDao userMapper = (UserDao) context.getBean("userDao2" ); List<User> userList = userMapper.getUserList(); for (User user:userList){ System.out.println(user); } } }
总结 : 整合到spring中以后可以完全不要mybatis的配置文件,除了这些方式可以实现整合之外,我们还 可以使用注解来实现,这个等我们后面学习SpringBoot的时候还会测试整合!
8 声明式事务 8.1 Spring事务简述 事务的ACID四个属性(熟背)。Spring支持编程式事务管理和声明式的事务管理。
编程式事务管理:
将事务管理代码嵌到业务方法中来控制事务的提交和回滚
缺点:必须在每个事务操作业务逻辑中包含额外的事务管理代码
声明式事务管理(更好用):
将事务管理代码从业务方法中分离出来,以声明的方式来实现事务管理。
将事务管理作为横切关注点,通过aop方法模块化。Spring中通过Spring AOP框架支持声明式事务 管理。
事务管理器 transactionManager
无论使用Spring的哪种事务管理策略(编程式或者声明式)事务管理器都是必须的。
就是 Spring的核心事务管理抽象,管理封装了一组独立于技术的方法。
使用Spring管理事务,注意头文件的约束导入 : tx
1 2 xmlns:tx="http://www.springframework.org/schema/tx" http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
配置事务管理器
1 2 3 <bean id ="transactionManager" class ="org.springframework.jdbc.datasource.DataSourceTransactionManager" > <property name ="dataSource" ref ="dataSource" /> </bean >
**spring事务传播特性:**事务传播行为就是多个事务方法相互调用时,事务如何在这些方法间传播。spring支持7种事务传播行为
propagation_requierd:如果当前没有事务,就新建一个事务,如果已存在一个事务中,加入到这 个事务中,这是最常见的选择。 (默认)
propagation_supports:支持当前事务,如果没有当前事务,就以非事务方法执行。
propagation_mandatory:使用当前事务,如果没有当前事务,就抛出异常。
propagation_required_new:新建事务,如果当前存在事务,把当前事务挂起。
propagation_not_supported:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
propagation_never:以非事务方式执行操作,如果当前事务存在则抛出异常。
propagation_nested:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与
propagation_required类似的操作
假设 ServiveX#methodX() 都工作在事务环境下(即都被 Spring 事务增强了),假设程序中存在如下的 调用链:Service1#method1()->Service2#method2()->Service3#method3(),那么这 3 个服务类的 3 个方法通过 Spring 的事务传播机制都工作在同一个事务中。
8.2 声明式事务的示例 这里从导入依赖开始、完整的以第二种方式整合一遍Mybatis,并且设置一个以AOP切入方式的声明式事务!!!很牛逼
1 导入Maven依赖包 junit、mybatis、mysql数据库、spring、aspectjweaver、mybatis-spring
2 数据库建表(省略)、并写一个和数据库对应的实体类User
3 Mybatis部分:Mapper接口、Mapper.xml中写SQL、写Mybatis的mybatis-config.xml配置文件
a 写一个UserMapper接口、里面查询、增加和删除的抽象方法
b 对应实现该接口方法的UserMapper.xml的SQL语句
c mybatis-config.xml中不用注册mapper了,写个别名就好了,甚至可省略
4 编写Spring的辅助配置文件spring-dao.xml;在配置声明式事务,并结合AOP实现事务的织入
5 编写UserMapper的实现类UserMapperImpl
6 真正的Spring配置文件 applicationContext.xml
7 测试方法
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 <dependencies > <dependency > <groupId > org.springframework</groupId > <artifactId > spring-webmvc</artifactId > <version > 5.2.8.RELEASE</version > </dependency > <dependency > <groupId > junit</groupId > <artifactId > junit</artifactId > <version > 4.12</version > </dependency > <dependency > <groupId > org.aspectj</groupId > <artifactId > aspectjweaver</artifactId > <version > 1.9.4</version > </dependency > <dependency > <groupId > mysql</groupId > <artifactId > mysql-connector-java</artifactId > <version > 5.1.47</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.1.9.RELEASE</version > </dependency > <dependency > <groupId > org.mybatis</groupId > <artifactId > mybatis-spring</artifactId > <version > 2.0.2</version > </dependency > <dependency > <groupId > org.projectlombok</groupId > <artifactId > lombok</artifactId > <version > 1.18.4</version > </dependency > </dependencies > <build > <resources > <resource > <directory > src/main/java</directory > <includes > <include > **/*.xml</include > </includes > <filtering > true</filtering > </resource > </resources > </build >
2 建表(省略)、并写一个和数据库对应的实体类User
1 2 3 4 5 6 7 8 @Data @AllArgsConstructor @NoArgsConstructor public class User { private int id; private String name; private String pwd; }
3 Mybatis部分:Mapper接口、Mapper.xml中写SQL、写Mybatis的mybatis-config.xml配置文件
//UserMapper接口
1 2 3 4 5 6 7 8 public interface UserMapper { public List<User> selectUser () ; public int addUser (User user) ; public int deleteUser (int id) ; }
UserMapper.xml
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="UTF8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > <mapper namespace ="com.kuang.mapper.UserMapper" > <select id ="selectUser" resultType ="user" > select * from mybatis.user; </select > <insert id ="addUser" parameterType ="user" > insert into mybatis.user (id, name, pwd) values (#{id}, #{name}, #{pwd}); </insert > <delete id ="deleteUser" parameterType ="int" > delete from mybatis.user where id=#{id} </delete > </mapper >
mybatis-config.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 <?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.kuang.pojo" /> </typeAliases > </configuration >
4 编写Spring的辅助配置文件spring-dao.xml;在配置声明式事务,并结合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 <?xml version="1.0" encoding="UTF8"?> <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 https://www.springframework.org/schema/tx/spring-tx.xsd" > <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=true& useUnicode=true& characterEncoding=UTF-8" /> <property name ="username" value ="root" /> <property name ="password" value ="526736" /> </bean > <bean id ="sqlSessionFactory" class ="org.mybatis.spring.SqlSessionFactoryBean" > <property name ="dataSource" ref ="dataSource" /> <property name ="configLocation" value ="classpath:mybatis-config.xml" /> <property name ="mapperLocations" value ="classpath:com/kuang/mapper/*.xml" /> </bean > <bean id ="sqlSession" class ="org.mybatis.spring.SqlSessionTemplate" > <constructor-arg index ="0" ref ="sqlSessionFactory" /> </bean > <bean id ="transactionManager" class ="org.springframework.jdbc.datasource.DataSourceTransactionManager" > <property name ="dataSource" ref ="dataSource" /> </bean > <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.kuang.mapper.*.*(..))" /> <aop:advisor advice-ref ="txAdvice" pointcut-ref ="txPointCut" /> </aop:config > </beans >
5 编写UserMapper的实现类UserMapperImpl
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public class UserMapperImpl extends SqlSessionDaoSupport implements UserMapper { public List<User> selectUser () { User user = new User(8 , "小王" , "2131231" ); UserMapper mapper = getSqlSession().getMapper(UserMapper.class); mapper.addUser(user); mapper.deleteUser(4 ); return mapper.selectUser(); } public int addUser (User user) { return getSqlSession().getMapper(UserMapper.class).addUser(user); } public int deleteUser (int id) { return getSqlSession().getMapper(UserMapper.class).deleteUser(id); } }
6 真正的Spring配置文件 applicationContext.xml
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 ="userMapper" class ="com.kuang.mapper.UserMapperImpl" > <property name ="sqlSessionFactory" ref ="sqlSessionFactory" /> </bean > </beans >
1 2 3 4 5 6 7 8 9 10 11 public class MyTest { public static void main (String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml" ); UserMapper userMapper = context.getBean("userMapper" , UserMapper.class); List<User> userList = userMapper.selectUser(); for (User user : userList) { System.out.println(user); } } }