Spring
1.什么是Spring?
耦合:类与类之间的关联关系。【低耦合】
A类 B类—test方法—A类中变量
我们在访问B类的test方法的时候,需要在B类中创建一个A类的对象。
A类与B类有了关联关系—【耦合】
内聚:类中的元素集中处理。【高内聚】
例如:打怪实例的时候,掉血这个特征是属于怪物的,因此上我们就需要为怪物这个类中添加一个掉血的方法。而不是将这个掉血的动作交给角色的攻击方法来实现。
编写程序的时候尽量做到低耦合【降低类与类之间的关联关系】,高内聚【将属于某一个类的动作,交由整个类中完成】,这样做有利于后期维护和升级。
Spring是一个开源的分层的javaSE/javaEE一站式的容器的轻量级的,解决业务逻辑层【Service】与web层和数据访问层之间的松耦合问题。
1.开源的
2.javaSE/javaEE一站式
3.容器框架
4.轻量级
解决业务逻辑层【Service】与web层和数据访问层之间的松耦合
2.Spring的结构组成
从下往上test,core容器,aop【面向切面编程】,web,data access
1.test部分只有一个模块:
spring-test:spring测试,提供junit与mock测试功能
spring-context-support:spring额外支持包,比如邮件服务、视图解析等
它们的依赖关系
2.core部分包含4个模块
spring-core:依赖注入IoC与DI的最基本实现
spring-beans:Bean工厂与bean的装配
spring-context:spring的context上下文即IoC容器
spring-expression:spring表达式语言
它们的完整依赖关系
3.aop部分包含4个模块
spring-aop:面向切面编程
spring-aspects:集成AspectJ
spring-instrument:提供一些类级的工具支持和ClassLoader级的实现,用于服务器spring-instrument-tomcat:针对tomcat的instrument实现
它们的依赖关系
4.web部分包含4个模块
spring-web:基础web功能,如文件上传
spring-webmvc:mvc实现
spring-webmvc-portlet:基于portlet的mvc实现
spring-struts:与struts的集成,不推荐,spring4不再提供
它们的依赖关系
5.data access部分包含5个模块
spring-jdbc:jdbc的支持
spring-tx:事务控制
spring-orm:对象关系映射,集成orm框架
spring-oxm:对象xml映射
spring-jms:java消息服务
它们的依赖关系
3.Spring的优点
Spring的出现解决了JavaEE实际问题:
1.方便解耦,简化开发:Spring是一个超级工厂(超级容器),可以将对象的创建和依赖关系交给Spring工厂去管理
2.AOP编程:Spring提供面向切面编程,可以方便的对程序进行运行监控、权限验证等操作
3.声明事务:只需要通过配置就可以完成对事务的管理,不需要手动编程
4.方便测试:Spring支持junit4,可以通过Spring注解方式测试程序
5.方便集成各种框架:Spring支持各种开源框架的集成。例如(struts、Hibernate、MyBaties等)
6.降低JavaEE API的使用难度: Spring对JavaEE开发中非常难用的API进行封装,使这些开发API应用难度降低。
4.Spring的核心技术
1.IoC(Inverse of Control 反转控制):将java对象创建和维护权利交由Spring工厂进行管理和维护。
2.DI(依赖注入):将某一个java类中的依赖对象快速的添加到另一个java类中。
3.AOP(Aspect Oriented Programming 面向切面编程),基于动态代理的功能增强方式[给自己的程序中添加一些系统需求的处理【日志管理,数据的安全性检查…】]。
4.事务管理的相关操作。
5.Spring整合/管理其他各层的框架【Spring集成web层SpringMVC/Spring整合数据访问层MyBatis】{SSM}
5.Spring的IoC(Inverse of Control 反转控制)
IoC(Inverse of Control 反转控制): 将java对象创建和维护权利交由Spring工厂进行管理和维护。
1.在没有使用IoC技术的时候,java对象的创建和维护权利是由程序开发者自己来创建和维护。
例如:
package com.click369.javabean;
public class StudentBean {
private int stuid;
private String stuname;
private int stuage;
public StudentBean(){}
public StudentBean(int stuid,String stuname,int stuage){
this.stuid=stuid;
this.stuname=stuname;
this.stuage=stuage;
}
public int getStuid() {
return stuid;
}
public void setStuid(int stuid) {
this.stuid = stuid;
}
public String getStuname() {
return stuname;
}
public void setStuname(String stuname) {
this.stuname = stuname;
}
public int getStuage() {
return stuage;
}
public void setStuage(int stuage) {
this.stuage = stuage;
}
@Override
public String toString() {
return "stuid=="+stuid+" stuname=="+stuname+" stuage=="+stuage;
}
}
/**
* 在没有使用Spring的时候,我们要想创建java对象,就得自己new
*/
@Test
public void test1(){
//自己new的java对象,java对象的创建是程序开发者自己创建维护
StudentBean stu=new StudentBean(1001,"zhangsan",23);
System.out.println(stu.toString());
}
使用Spring框架
1.导入依赖包
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
2.在有使用IoC技术的时候,java对象的创建和维护权利就要由程序开发者自己,转移给Spring工厂去创建和维护。如果我们编写的程序中需要使用Spring工厂创建的java对象,那么就需要从Spring工厂中得到由Spring工厂创建的java对象.
1.如何让Spring工厂创建对象?
答案:通过在Spring的配置文件中通过元素配置由Spring工厂所要创建的java对象。
在工程的src/main/resources下创建一个【applicationContext.xml】文件,spring核心配置文件
<?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">
</beans>
在【applicationContext.xml】文件,spring核心配置文件中配置需要由Spring工厂创建对象的java类
对于Spring而言,它认为出现在Spring中的所有元素【java类/java接口】,都是一个组件,在程序中组件就是bean的意思,所以我们所说的javabean就是一个java组件,因此上我们在Spring的配置文件中通过元素配置由Spring工厂所要创建的java对象。
具体配置:
<bean id=”对象名称” class=”被创建的java对象的包名+类名/接口名”> </bean>
例如:
<bean id="student" class="com.click369.javabean.StudentBean"></bean>
3.如何从Sprign工厂所创建的众多对象中得到自己需要使用的java对象?
答案:首先得到Spring工厂对象,然后通过这个工厂对象提供的方法getBean(“”)将自己需要的对象得到。
4.Spring工厂对象有那些,如何创建Spring工厂对象,在创建Spring工厂对象的时候需要什么?
3.1 Spring工厂对象有那些。
1.BeanFactory接口----Spring工厂对象
2.ApplicationContex接口------Spring工厂对象
ApplicationContext接口这个Spring工厂对象是BeanFactory接口的子接口。
3.2 如何创建Spring工厂对象
1.ClassPathXmlApplicationContext类 – new ClassPathXmlApplicationContext()可以创建出BeanFactory接口对象/ApplicationContext对象
表示:通过查找类路径加载一个Xml文件创建Spring工厂对象。【相对路径下查找Spring核心配置文件】
2. FileSystemXmlApplicationContext类 ---new FileSystemXmlApplicationContext可以创建出BeanFactory接口对象/ApplicationContext对象
表示:通过在系统文件类路径中加载一个Xml文件创建Spring工厂对象。【绝对路径下查找Spring核心配置文件】
例如:
//创建Spring工厂对象–BeanFactory接口
//1.通过查找类路径加载一个Xml文件创建Spring工厂对象。【相对路径下查找Spring核心配置文件】
BeanFactory beanFactory1=new ClassPathXmlApplicationContext("applicationContext.xml");
//2.通过在系统文件类路径中加载一个Xml文件创建Spring工厂对象。【绝对路径下查找Spring核心配置文件】
BeanFactory beanFactory2=new FileSystemXmlApplicationContext("F:\\20190801\\Spring\\applicationContext.xml");
//创建Spring工厂对象--ApplicationContex接口
//1.通过查找类路径加载一个Xml文件创建Spring工厂对象。【相对路径下查找Spring核心配置文件】
ApplicationContext ac1=new ClassPathXmlApplicationContext("applicationContext.xml");
//2.通过在系统文件类路径中加载一个Xml文件创建Spring工厂对象。【绝对路径下查找Spring核心配置文件】
ApplicationContext ac2=new FileSystemXmlApplicationContext("F:\\20190801\\Spring\\applicationContext.xml");
3.3 在创建Spring工厂对象的时候需要什么?
需要一个Xml文件【Spring的核心配置文件】
通过Spring工厂对象,调用getBean()得到自己需要的java对象
//StudentBean stu=(StudentBean)ac1.getBean("student");
StudentBean stu=ac1.getBean(StudentBean.class);
stu.setStuid(1001);
stu.setStuname("zhangsan");
stu.setStuage(23);
stu.setStuaddress("西安");
System.out.println(stu.toString());
IOC[控制反转]–将java对象的创建和维护权利,从开发者自己的手中,转移到Spring身上,这种对象的创建和维护权利的转移就叫控制反转【IOC】
6.Bean实例化4种方式
如何通过bean标签,告诉spring该用什么样的方式最终得到某个类的对象。【bean的实例化】
1.1无参数构造方法(开发最常用)
package com.click369.javabean;
public class StudentBean {
private int stuid;
private String stuname;
private int stuage;
public StudentBean(){}
.............
}
编写Spring的配置文件:【applicationContext.xml/自己起名】{src/main/resources}
<!-- 无参数构造方法实例化bean -->
<!-- id:对象名称 -->
<!-- class:被创建对象的java类的包名+类名 -->
<bean id="stu" class="com.click369.javabean.StudentBean"></bean>
测试
//创建Spring工厂对象
ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
//通过getBean方法从Spring工厂对象中得到需要的java类对象
StudentBean stu= (StudentBean)applicationContext.getBean("stu");
//使用由Spring工厂对象实例化好的java对象
stu.setStuid(1001);
stu.setStuname("lisi");
stu.setStuage(24);
System.out.println("stu=="+stu.toString());
1.2静态工厂方法实例化bean
静态工厂方法:在一个类中书写静态的方法,这个方法返回某个Bean的对象(在方法中创建Bean的对象)。
实体类:
package com.click369.javabean;
public class StudentBean {
private int stuid;
private String stuname;
private int stuage;
public StudentBean(){}
.............
}
创建一个静态工厂方法类,提供一个静态方法,让这个静态方法返回一个实体类的对象
package com.click369.javabean;
/**
* 静态工厂方法类
* @author Administrator
*
*/
public class StaticFactoryMethodClass {
/**
* 静态方法,让这个静态方法返回一个实体类的对象
* @return
*/
public static StudentBean getStaticStudentBean(){
return new StudentBean();
}
}
编写Spring配置
<!-- 静态工厂方法实例化bean的配置 -->
<!-- id:对象名称 -->
<!-- factory-method:配置静态工厂方法 -->
<!-- class:配置静态工厂方法类【包名+类名】 -->
<bean id="student" factory-method="getStaticStudentBean" class="com.click369.javabean.StaticFactoryMethodClass"></bean>
测试代码:
ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
StudentBean stu= applicationContext.getBean(StudentBean.class);
stu.setStuid(1002);
stu.setStuname("wangwu");
stu.setStuage(25);
System.out.println("stu=="+stu.toString());
1.3实例工厂方法实例化bean
实体类:
package com.click369.javabean;
public class StudentBean {
private int stuid;
private String stuname;
private int stuage;
public StudentBean(){}
.............
}
创建一个工厂类,提供实例方法,这个实例方法返回java实体类的对象
package com.click369.javabean;
/**
* 工厂类
* @author Administrator
*
*/
public class StudentFactory {
/**
* 实例方法,返回实体类对象
* @return
*/
public StudentBean getStudentBean(){
return new StudentBean();
}
}
Spring配置文件的编写:
<!-- 实例工程方法实例化bean的配置 -->
<!-- 创建实例工厂类对象 -->
<bean id="studentFactory" class="com.click369.javabean.StudentFactory"></bean>
<!-- 配置得到实体类对象 -->
<!-- id:对象名称 -->
<!-- factory-bean:实例工厂类对象 -->
<!-- factory-method:实例工厂类中创建实体类的方法 -->
<bean id="student" factory-bean="studentFactory" factory-method="getStudentBean"></bean>
测试:
ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
StudentBean stu= applicationContext.getBean(StudentBean.class);
stu.setStuid(1002);
stu.setStuname("wangwu");
stu.setStuage(25);
System.out.println("stu=="+stu.toString());
1.4FactoryBean接口方式实例化bean
FactoryBean是Spring提供的接口,专门用于对bean进行初始化操作的。
如果bean需要使用这种方式进行初始化,那么需要定义类实现这个FactoryBean接口,在实现类中复写getObject的方法。
实体类:
package com.click369.javabean;
public class StudentBean {
private int stuid;
private String stuname;
private int stuage;
public StudentBean(){}
.............
}
创建一个类,实现FactoryBean接口,重写getObject的方法,返回实体类对象。
package com.click369.factory;
import org.springframework.beans.factory.FactoryBean;
import com.click369.javabean.StudentBean;
public class CreateObject implements FactoryBean<StudentBean>{
@Override
public StudentBean getObject() throws Exception {
return new StudentBean();
}
@Override
public Class<?> getObjectType() {
return StudentBean.class;
}
}
Spring配置文件:
<!-- FactoryBean实例化Bean的配置 -->
<!-- id:对象名称 -->
<!-- class:实现FactoryBean接口的java类的包名+类名 -->
<bean id="student" class="com.click369.factory.CreateObject"></bean>
测试:
package test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.click369.javabean.StudentBean;
public class TestMain {
public static void main(String[] args) {
ApplicationContext ac1=new ClassPathXmlApplicationContext("applicationContext.xml");
StudentBean stu=ac1.getBean(StudentBean.class);
stu.setStuid(1001);
stu.setStuname("zhangsan");
stu.setStuage(23);
stu.setStuaddress("西安");
System.out.println(stu.toString());
}
}
7.FactoryBean接口与BeanFactory接口的区别
共同点:都是接口。
不同点:FactoryBean是Spring提供的专门用来实例化java类的接口。【创造】
BeanFactory接口表示一个Spring工厂对象【Spring容器对象】,包含了实例化好的java类对象。【管理】
BeanFactory接口有一个常用的子接口ApplicationContext接口,我们通常使用ApplicationContext接口充当Spring工厂对象【Spring容器对象】。
8.bean的作用域
bean的作用域:主要是指Spring创建的Bean对象是单例、多例、request、session级别。
有点像JSP动作元素useBean的page/request/session/application.
singleton: 单例模式【在一个spring容器中,对象只有一个实例。(默认值)】
prototype:多例模式/原型模式【在一个spring容器中,存在多个实例,每次getBean 返回一个新的实例。】
request:该属性仅对HTTP请求产生作用,使用该属性定义Bean时,每次HTTP请求都会创建一个新的Bean,适用于WebApplicationContext环境。【一次请求一个对象】
session:该属性仅用于HTTP Session,同一个Session共享一个Bean实例。不同Session使用不同的实例。【同一次回话中的对象都是相同的】
global session:该属性仅用于HTTP Session,同session作用域不同的是,所有的Session共享一个Bean实例。【多个session共享一个对象】
下面重点讨论singleton、prototyp作用域,request,session和global-session类作用域放到Spring MVC章节讨论,这里不再做详细讲述。
通过在配置Spring配置文件是设置bean元素的scope属性设置bean的作用域:
bean元素的scope属性:singleton,prototype,request,session,global session。
例如:
<bean id=”对象名称”
class=”被实例化的javabean类”
scope=”singleton/prototype/request/session/global session”>
1.singleton: 单例模式【在一个spring容器中,对象只有一个实例。(默认值)】
package com.click369.javabean;
public class StudentBean {
private int stuid;
private String stuname;
private int stuage;
public StudentBean(){}
.......
}
<!-- id:对象名称 -->
<!-- class:被创建对象的java类的包名+类名 -->
<!-- scope:设置作用域 -->
<bean id="stu" class="com.click369.javabean.StudentBean" scope="singleton"></bean>
或者
<bean id="stu" class="com.click369.javabean.StudentBean"></bean>
ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
StudentBean stu1=applicationContext.getBean(StudentBean.class);
StudentBean stu2=applicationContext.getBean(StudentBean.class);
System.out.println("stu1=="+stu1.hashCode());
System.out.println("stu2=="+stu2.hashCode());
prototype:多例模式/原型模式【在一个spring容器中,存在多个实例,每次getBean 返回一个新的实例。】
package com.click369.javabean;
public class StudentBean {
private int stuid;
private String stuname;
private int stuage;
public StudentBean(){}
.......
}
<!-- 无参数构造方法实例化bean的配置 -->
<!-- id:对象名称 -->
<!-- class:被创建对象的java类的包名+类名 -->
<!-- scope:设置作用域 -->
<bean id="stu" class="com.click369.javabean.StudentBean" scope="prototype"></bean>
ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
StudentBean stu1=applicationContext.getBean(StudentBean.class);
StudentBean stu2=applicationContext.getBean(StudentBean.class);
System.out.println("stu1=="+stu1.hashCode());
System.out.println("stu2=="+stu2.hashCode());
9.bean的生命周期
Spring工厂对象【Spring容器对象】负责创建对象,初始化对象,销毁对象。
也就是说任何一个交给Spring的Bean,它的生命周期统一由Spring容器维护。
测试Bean的创建生命周期:
package com.click369.javabean;
public class StudentBean {
/**
* 测试StudentBean类对象的创建
*/
public StudentBean(){
System.out.println("测试StudentBean类对象的创建");
}
}
<!-- 无参数构造方法实例化bean的配置 -->
<!-- id:对象名称 -->
<!-- class:被创建对象的java类的包名+类名 -->
<bean id="student" class="com.click369.javabean.StudentBean"></bean>
测试:
ApplicationContext applicationContext=new ClassPathXmlApplicationContext(“applicationContext.xml”);
测试初始化:
package com.click369.javabean;
public class StudentBean {
/**
* 测试StudentBean类对象的创建
*/
public StudentBean(){
System.out.println("测试StudentBean类对象的创建");
}
/**
* 测试StudentBean类对象的初始化
*/
public void initStudentBean(){
System.out.println("测试StudentBean类对象的初始化");
}
}
<!-- 无参数构造方法实例化bean的配置 -->
<!-- id:对象名称 -->
<!-- class:被创建对象的java类的包名+类名 -->
<!-- init-method:配置对象的初始化方法 -->
<bean id="student" class="com.click369.javabean.StudentBean" init-method="initStudentBean"></bean>
测试:
ApplicationContext applicationContext=new ClassPathXmlApplicationContext(“applicationContext.xml”);
测试销毁:
Bean的销毁必须满足两个条件:
1、bean必须是单例的。
2、bean的所在的容器(Spring)必须手动关闭。
package com.click369.javabean;
public class StudentBean {
/**
* 测试StudentBean类对象的创建
*/
public StudentBean(){
System.out.println("测试StudentBean类对象的创建");
}
/**
* 测试StudentBean类对象的初始化
*/
public void initStudentBean(){
System.out.println("测试StudentBean类对象的初始化");
}
/**
* 测试StudentBean类对象的销毁
*/
public void destroyStudentBean(){
System.out.println("测试StudentBean类对象的销毁");
}
}
<!-- 无参数构造方法实例化bean的配置 -->
<!-- id:对象名称 -->
<!-- class:被创建对象的java类的包名+类名 -->
<!-- init-method:配置对象的初始化方法 -->
<!-- destroy-method:配置对象的销毁方法 -->
<bean id="student" class="com.click369.javabean.StudentBean" init-method="initStudentBean" destroy-method="destroyStudentBean"></bean>
测试类:
ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
StudentBean stu1=(StudentBean)applicationContext.getBean("student");
System.out.println("stu1=="+stu1.hashCode());
//关闭容器
((ClassPathXmlApplicationContext)applicationContext).close();
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200730164032927.png)
Bean的生命周期,先创建对象【构造方法执行】,再初始化【自己定义的初始化方法需要通过init-method属性配置】,当关闭容器的时候销毁对象【自己定义的销毁方法需要通过destroy-method属性配置】。
10.Spring的依赖注入是什么?实现方式有几种?每一种如何操作?
DI–依赖注入,建立在IoC[控制反转]基础之上的,没有控制反转就谈不上依赖注入。
解释依赖注入的话,需要先引入两个概念,第一个就是调用者类,第二个就是被调用者类。
Public class Person{
}
Public class Student{
Public Person person;
Public void getStudentinfo(){
}
}
Student类就是一个调用者类
Person类就是一个被调用者类
Person类的对象就是Student类的依赖对象。
依赖注入–在调用者类中将被调用者类的对象,添加到调用者类中这个过程就是依赖注入。
在这个过程中被调用者类的对象就是调用者类的依赖对象。
Servlet----Service
在Servlet中创建了Service
Servlet–调用者类
Service–被调用者类
把Service添加到Servlet中的过程叫依赖注入
Service是Servlet的依赖对象
依赖注入的方式
1.构造方法注入
创建被调用者类
package com.click369.javabean;
/**
* 被调用者类
* @author Administrator
*
*/
public class PersonBean {
public PersonBean(){
System.out.println("PersonBean--被调用者类的构造方法");
}
public void testPerson(){
System.out.println("测试被调用者类");
}
}
调用者类
package com.click369.javabean;
/**
* 调用者类
* @author Administrator
*
*/
public class StudentBean {
//依赖对象
public PersonBean personBean;
public StudentBean(PersonBean personBean){
System.out.println("StudentBean--调用者类的构造方法");
this.personBean=personBean;
}
public void testStudent(){
System.out.println("测试StudentBean类");
personBean.testPerson();
}
}
Spring配置文件
<!-- 创建被调用者类PersonBean -->
<bean id="person" class="com.click369.javabean.PersonBean"></bean>
<!-- 创建调用者类StudentBean -->
<bean id="student" class="com.click369.javabean.StudentBean">
<!-- 构造方法注入 -->
<!-- index:构造方法参数的索引值 -->
<!-- ref:引用对象 -->
<constructor-arg index="0" ref="person"></constructor-arg>
</bean>
测试
ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
StudentBean stu1=(StudentBean)applicationContext.getBean("student");
stu1.testStudent();
2.Set方法注入
被调用者类:
package com.click369.javabean;
/**
* 被调用者类
* @author Administrator
*
*/
public class PersonBean {
public PersonBean(){
System.out.println("PersonBean--被调用者类的构造方法");
}
public void testPerson(){
System.out.println("测试被调用者类");
}
}
调用者类
package com.click369.javabean;
/**
* 调用者类
* @author Administrator
*
*/
public class StudentBean {
//依赖对象
public PersonBean personBean;
//为依赖对象提供一个set方法
public void setPersonBean(PersonBean personBean) {
this.personBean = personBean;
}
public void testStudent(){
System.out.println("测试StudentBean类");
personBean.testPerson();
}
}
Spring配置文件:
<!-- 创建被调用者类PersonBean -->
<bean id="person" class="com.click369.javabean.PersonBean"></bean>
<!-- 创建调用者类StudentBean -->
<bean id="student" class="com.click369.javabean.StudentBean">
<!-- set方法注入被调用者类 -->
<!-- name:成员变量名称【依赖对象名称】 -->
<!-- ref:引用对象 -->
<property name="personBean" ref="person"></property>
</bean>
测试:
ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
StudentBean stu1=(StudentBean)applicationContext.getBean("student");
stu1.testStudent();
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200730164239255.png)
11.Spring的自动装配策略
11.注入非集合型的数据
创建对象型java类
package com.click369.javabean;
public class UserBean {
public String testUser(){
return "测试注入UserBean";
}
}
创建StudentBean类,提供不同类型的成员变量【int double char boolean String java.util.Date
com.click369.javabean.UserBean】
package com.click369.javabean;
import java.util.Date;
/**
* StudentBean类
* @author Administrator
*
*/
public class StudentBean {
private int stuid;
private double stuheight;
private char stusex;
private boolean stuboolean;
private String stuname;
private Date studay;
private UserBean userbean;
public int getStuid() {
return stuid;
}
public void setStuid(int stuid) {
this.stuid = stuid;
}
public double getStuheight() {
return stuheight;
}
public void setStuheight(double stuheight) {
this.stuheight = stuheight;
}
public char getStusex() {
return stusex;
}
public void setStusex(char stusex) {
this.stusex = stusex;
}
public boolean isStuboolean() {
return stuboolean;
}
public void setStuboolean(boolean stuboolean) {
this.stuboolean = stuboolean;
}
public String getStuname() {
return stuname;
}
public void setStuname(String stuname) {
this.stuname = stuname;
}
public Date getStuday() {
return studay;
}
public void setStuday(Date studay) {
this.studay = studay;
}
public UserBean getUserbean() {
return userbean;
}
public void setUserbean(UserBean userbean) {
this.userbean = userbean;
}
@Override
public String toString() {
return stuid+" "+stuname+" "+stusex+" "+stuheight+" "+stuboolean+" "+studay+" "+userbean.testUser();
}
}
Spring配置文件:
测试:
ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
StudentBean stu1=(StudentBean)applicationContext.getBean("student");
System.out.println(stu1.toString());
12.注入集合型数据【String】
StudentBean类
package com.click369.javabean;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
/**
* StudentBean类
* @author Administrator
*
*/
public class StudentBean {
private String stringArray[];
private List<String> stringList;
private Set<String> stringSet;
private Map<String,String> stringMap;
private Properties myProperties;
public String[] getStringArray() {
return stringArray;
}
public void setStringArray(String[] stringArray) {
this.stringArray = stringArray;
}
public List<String> getStringList() {
return stringList;
}
public void setStringList(List<String> stringList) {
this.stringList = stringList;
}
public Set<String> getStringSet() {
return stringSet;
}
public void setStringSet(Set<String> stringSet) {
this.stringSet = stringSet;
}
public Map<String, String> getStringMap() {
return stringMap;
}
public void setStringMap(Map<String, String> stringMap) {
this.stringMap = stringMap;
}
public Properties getMyProperties() {
return myProperties;
}
public void setMyProperties(Properties myProperties) {
this.myProperties = myProperties;
}
}
Spring配置文件
<?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">
<!-- 创建StudentBean对象,并通过set方式为集合型成员变量赋初始值-->
<bean id="student" class="com.click369.javabean.StudentBean">
<!-- 数组 -->
<property name="stringArray">
<array>
<value>zhangsan</value>
<value>lisi</value>
<value>wangwu</value>
</array>
</property>
<!-- list -->
<property name="stringList">
<list>
<value>西安</value>
<value>北京</value>
<value>上海</value>
</list>
</property>
<!-- set -->
<property name="stringSet">
<set>
<value>javaSE</value>
<value>javaEE</value>
<value>javaME</value>
</set>
</property>
<!-- Map -->
<!-- key属性的值不能是key -->
<!-- value属性的值不能是value -->
<property name="stringMap">
<map>
<entry key="age">
<value>23</value>
</entry>
<entry key="height" value="167.5"></entry>
<entry key="sex" value="男"></entry>
</map>
</property>
<!-- properties -->
<property name="myProperties">
<props>
<prop key="mydirver">com.mysql.jdbc.Driver</prop>
<prop key="myusername">root</prop>
<prop key="mypassword">123456</prop>
</props>
</property>
</bean>
</beans>
测试:
@Test
public void test1()throws Exception{
ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
StudentBean stu1=(StudentBean)applicationContext.getBean("student");
System.out.println("测试数组数据开始");
for(String var1:stu1.getStringArray()){
System.out.println("array=="+var1);
}
System.out.println("测试数组数据结束");
System.out.println("测试Lsit数据开始");
for(String var2:stu1.getStringList()){
System.out.println("list=="+var2);
}
System.out.println("测试List数据结束");
System.out.println("测试Set数据开始");
for(String var3:stu1.getStringSet()){
System.out.println("set=="+var3);
}
System.out.println("测试Set数据结束");
System.out.println("测试Map数据开始");
for(Map.Entry<String,String> entry:stu1.getStringMap().entrySet()){
System.out.println("map=="+entry.getKey()+":"+entry.getValue());
}
System.out.println("测试Map数据结束");
System.out.println("测试Properties数据开始");
Properties props=stu1.getMyProperties();
Iterator<String> propkeys=props.stringPropertyNames().iterator();
while(propkeys.hasNext()){
String keyvalue=propkeys.next();
String myvalue=props.getProperty(keyvalue);
System.out.println("Properties=="+keyvalue+"-"+myvalue);
}
System.out.println("测试Properties数据结束");
}
![在这里插入图片描述](https://img-blog.csdnimg.cn/2020073016463327.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQ5NTg1MjI4,size_16,color_FFFFFF,t_70)
13.注入集合型数据【对象型】
UserBean类
package com.click369.javabean;
public class UserBean {
private int userid;
private String username;
private String useraddress;
public int getUserid() {
return userid;
}
public void setUserid(int userid) {
this.userid = userid;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getUseraddress() {
return useraddress;
}
public void setUseraddress(String useraddress) {
this.useraddress = useraddress;
}
@Override
public String toString() {
return userid+" "+username+" "+useraddress;
}
}
StudentBean类
package com.click369.javabean;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* StudentBean类
* @author Administrator
*
*/
public class StudentBean {
private UserBean userArray[];
private List<UserBean> userList;
private Set<UserBean> userSet;
private Map<String,UserBean> userMap;
public UserBean[] getUserArray() {
return userArray;
}
public void setUserArray(UserBean[] userArray) {
this.userArray = userArray;
}
public List<UserBean> getUserList() {
return userList;
}
public void setUserList(List<UserBean> userList) {
this.userList = userList;
}
public Set<UserBean> getUserSet() {
return userSet;
}
public void setUserSet(Set<UserBean> userSet) {
this.userSet = userSet;
}
public Map<String, UserBean> getUserMap() {
return userMap;
}
public void setUserMap(Map<String, UserBean> userMap) {
this.userMap = userMap;
}
}
Spring的配置文件:
<?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">
<!-- 创建两个userbean对象 -->
<bean id="user1" class="com.click369.javabean.UserBean">
<property name="userid" value="1001"></property>
<property name="username" value="zhangsan"></property>
<property name="useraddress" value="西安"></property>
</bean>
<bean id="user2" class="com.click369.javabean.UserBean">
<property name="userid" value="1002"></property>
<property name="username" value="李四"></property>
<property name="useraddress" value="北京"></property>
</bean>
<!-- 创建StudentBean对象,并通过set方式为集合型成员变量赋初始值-->
<bean id="student" class="com.click369.javabean.StudentBean">
<!-- 数组 -->
<property name="userArray">
<array>
<ref bean="user1"/>
<ref bean="user2"/>
</array>
</property>
<!-- List -->
<property name="userList">
<list>
<ref bean="user1"/>
<ref bean="user2"/>
</list>
</property>
<!-- Set -->
<property name="userSet">
<set>
<ref bean="user1"/>
<ref bean="user2"/>
</set>
</property>
<!-- Set -->
<property name="userMap">
<map>
<entry key="myuser1" value-ref="user1"></entry>
<entry key="myuser2" value-ref="user2"></entry>
</map>
</property>
</bean>
</beans>
测试:
@Test
public void test1()throws Exception{
ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
StudentBean stu1=(StudentBean)applicationContext.getBean("student");
System.out.println("测试对象型数组数据开始");
for(UserBean user1:stu1.getUserArray()){
System.out.println("userarray=="+user1.toString());
}
System.out.println("测试对象型数组数据结束");
System.out.println("测试对象型List数据开始");
for(UserBean user2:stu1.getUserList()){
System.out.println("userlist=="+user2.toString());
}
System.out.println("测试对象型List数据结束");
System.out.println("测试对象型Set数据开始");
for(UserBean user3:stu1.getUserSet()){
System.out.println("userset=="+user3.toString());
}
System.out.println("测试对象型Set数据结束");
System.out.println("测试对象型Map数据开始");
for(Map.Entry<String,UserBean> entery:stu1.getUserMap().entrySet()){
System.out.println("usermap=="+entery.getKey()+":"+entery.getValue().toString());
}
System.out.println("测试对象型Map数据结束");
}
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200730164652325.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQ5NTg1MjI4,size_16,color_FFFFFF,t_70)
12.autowired和resource的区别
@Autowired 是根据对应的属性的类型找到对应的bean进行自动注入。
@Service 标注类是一个业务访问类
@Service添加在业务实现类上表示该类是一个业务访问类,默认的业务访问类的名称就是类名。
@Service(“自定义的名称”)添加在业务实现类上表示该类是一个业务访问类,使用自动定义的名称
在上面的这个实例中添加业务访问接口以及实现类
package com.click369.service;
import java.util.List;
import com.click369.javabean.UserBean;
public interface UserService {
UserBean queryUserNameAadPass(UserBean user);
List<UserBean> queryUser();
}
package com.click369.service.impl;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.click369.javabean.UserBean;
import com.click369.mapper.UserMapper;
import com.click369.service.UserService;
//@Service
//表示该类是一个业务访问类,默认的业务访问类的名称就是类名。
@Service("userService")
//表示该类是一个业务访问类,使用自动定义的名称
public class UserServiceImpl implements UserService{
//依赖对象的自动注入【无需在UserServiceImpl类中提供依赖对象的set方法,无需在SPring的配置文件中配置注入】
@Autowired
private UserMapper userMapper;
@Override
public UserBean queryUserNameAadPass(UserBean user) {
return userMapper.selectUserNameAndPass(user);
}
@Override
public List<UserBean> queryUser() {
return userMapper.selectUser();
}
}
<!-- 开启注解功能 -->
<context:annotation-config/>
<!-- 配置自动扫描service包 -->
<context:component-scan base-package="com.click369.service.impl"></context:component-scan>
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService service = (UserService) context.getBean("userService");
List<UserBean> userlist = service.queryUser();
for(UserBean user:userlist){
System.out.println(user.getUserid()+" "+user.getUsername());
}
@Resource注解注入复杂类型数据
package com.click369.service.impl;
import java.util.List;
import javax.annotation.Resource;
import org.springframework.stereotype.Service;
import com.click369.javabean.UserBean;
import com.click369.mapper.UserMapper;
import com.click369.service.UserService;
@Service("userService")
public class UserServiceImpl implements UserService {
//定义依赖对象
@Resource
private UserMapper myUserMapper;
.......................
}
创建LoaderServlet
package com.click369.ssmj.servlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import org.springframework.context.ApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
public class LoaderServlet extends HttpServlet{
private static ApplicationContext context=null;
@Override
public void init() throws ServletException {
context=WebApplicationContextUtils.getWebApplicationContext(this.getServletContext());
}
public static Object getServiceObject(String servicename){
Object serviceObject=null;
serviceObject=context.getBean(servicename);
return serviceObject;
}
}
创建用户访问的Servlet
package com.click369.ssmj.servlet;
import java.io.IOException;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.click369.ssmj.javabean.UserBean;
import com.click369.ssmj.service.UserService;
public class LoginServlet extends HttpServlet{
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("utf-8");
resp.setCharacterEncoding("utf-8");
//得到用户名和密码
String username=req.getParameter("username");
String userpass=req.getParameter("password");
//封装UserBean
UserBean user=new UserBean();
user.setUsername(username);
user.setUserpass(userpass);
//得到UserServie
UserService userservice=LoaderServlet.getUserService();
UserBean userBean=userservice.queryUserNameAndPass(user);
if(userBean!=null){
List<UserBean> userList=userservice.queryUser();
req.getSession().setAttribute("username", username);
req.getSession().setAttribute("userList", userList);
resp.sendRedirect("main.jsp");
}else{
req.setAttribute("error","用户名密码错误!");
req.getRequestDispatcher("login.jsp").forward(req, resp);
}
}
}
配置web.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<!-- 配置加载Spring配置文件 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- 配置LoaderServlet -->
<servlet>
<servlet-name>loaderservlet</servlet-name>
<servlet-class>com.click369.ssmj.servlet.LoaderServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<!-- 配置LoginServlet -->
<servlet>
<servlet-name>login</servlet-name>
<servlet-class>com.click369.ssmj.servlet.LoginServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>login</servlet-name>
<url-pattern>/login</url-pattern>
</servlet-mapping>
</web-app>
创建jsp页面[login.jsp/main.jsp]
<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Insert title here</title>
</head>
<body>
<center>
<c:if test="${not empty error}">
<font color="red">${error}</font>
</c:if>
<form action="login" method="get">
用户名:<input type="text" name="username" ><br>
密码:<input type="password" name="password" ><br>
<input type="submit" value="登陆">
</form>
</center>
</body>
</html>
<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Insert title here</title>
</head>
<body>
<c:if test="${empty username}">
<jsp:forward page="login.jsp"></jsp:forward>
</c:if>
<center>
<h1>${username},登陆成功!</h1>
<hr>
<table border="1px" width="500px">
<tr align="center">
<td>编号</td>
<td>用户名</td>
<td>密码</td>
<td>年龄</td>
<td>地址</td>
</tr>
<c:forEach items="${userList}" var="user">
<tr align="center">
<td>${user.userid}</td>
<td>${user.username}</td>
<td>${user.userpass}</td>
<td>${user.userage}</td>
<td>${user.useraddress}</td>
</tr>
</c:forEach>
</table>
</center>
</body>
</html>
作业:@Autowired注解与@Resource注解的区别?
-
@Autowired
由spring提供,只按照byType注入 -
@Resource
由J2EE提供,默认是按照byName自动注入
@Resource有两个重要的属性,name和type:
Spring将@Resource注解的name属性解析为bean的名字,type属性则解析为bean的类型。所以如果使用name属性,则使用byName的自动注入策略;而使用type属性则使用byType自动注入策略;如果既不指定name也不指定type属性,这时通过反射机制使用byName自动注入策略。
@Resource装配的顺序:
如果同时指定了name和type属性,则从spring上下问中找到唯一匹配的bean进行装配,如果没有找到,则会抛出异常。
如果指定了name属性,则从spring上下文中查找名称(id)匹配的bean进行装配,找不到则抛出异常。
如果指定type属性,则从spring上下文中找到类型匹配的唯一bean进行装配,找不到或者是找到多个,则抛出异常。
如果既没有指定name属性,也没有指定type属性,则默认是按照byName的方式进行装配;如果没有匹配,则返回一个原始的类型进行装配,如果匹配则自动装配。
@Resource的作用是相当于@Autowired,只不过@Autowired是按照byType进行装配。
-
使用区别
@Resource和@Autowired都可以用来装配bean,都可以写在字段上或者是写在setter方法上。
@Autowired默认是按照byType进行装配的,所以默认情况下是必须依赖的对象存在,如果要允许为空,可以设置它的required属性为false,如果想使用byName进行装配,可以结合@Qualifier注解进行使用。
@Resource默认是按照byName进行装配的,名称可以通过name属性进行制定,如果没有指定name属性,注解写在字段上时,默认是取字段名作为名称进行查找。如果注解写在setter方法上则默认是取属性的名称进行装配,当找不到与名称匹配的bean时才按照类型进行装配。但是值得注意的是,一旦指定了name属性,就会按照名称进行装配。
推荐使用@Resource注解在字段上,这样就不需要写setter方法了,并且这个属性是属于J2EE的,从而可以减少对spring的耦合 -
总结的规律
如果@Resource或者是@Autowired注解写在setter方法之上,则程序会走set方法内部,如果是写在filed上,则不糊走set方法内部。
13.@Component
注解
开发中难免会遇到这个这个注解@Component
@controller 控制器(注入服务)
用于标注控制层,相当于struts中的action层
@service 服务(注入dao)
用于标注服务层,主要用来进行业务的逻辑处理
@repository(实现dao访问)
用于标注数据访问层,也可以说用于标注数据访问组件,即DAO组件
.
@component
(把普通pojo实例化到spring容器中,相当于配置文件中的
)
泛指各种组件,就是说当我们的类不属于各种归类的时候(不属于@Controller、@Services等的时候),我们就可以使用@Component来标注这个类。
遇到的问题
踩到一个坑,有一个接口,在这个接口的实现类里,需要用到@Autowired
注解,一时大意,没有在实现类上加上@Component
注解,导致了Spring报错,找不到这个类
一旦使用关于Spring的注解出现在类里,例如我在实现类中用到了@Autowired
注解,被注解的这个类是从Spring容器中取出来的,那调用的实现类也需要被Spring容器管理,加上@Component
@Component("conversionImpl")
public class ConversionImpl implements Conversion {
@Autowired
private RedisClient redisClient;
}
14.什么是AOP?
AOP (Aspect Oriented Programing) 称为:面向切面编程,它是一种编程思想。
AOP采取横向抽取机制,取代了传统纵向继承体系重复性代码的编写方式(性能监视、事务管理、安全检查、缓存,日志记录等)。
通常情况下一个系统/软件的需求有2种:
1.业务需求:实现具体某一个业务逻辑功能的实现过程。【添加,删除,修改,查询等等】
2.系统需求:在整个系统运行的过程中帮助完善系统业务需求的功能【性能监视,事务管理,安全检查,缓存,日志记录等】
现在我们需要完成的动作就是在需要使用系统需求的位置能够快速的将系统需求植入给必要的业务需求功能中。
完成上述动作的方式有2中:
1.传统纵向继承体系【静态代理】
1.1 父子模式
Public class StudentService{
Public void insert(){
System.out.println(“执行添加的业务需求”);
}
Public void update(){
System.out.println(“执行修改的业务需求”);
}
Public void delete(){
System.out.println(“执行删除的业务需求”);
}
Public void select(){
System.out.println(“执行查询的业务需求”);
}
}
Public class StudentSunService extends StudentService{
Public void saveLog(){
System.out.println(“记录日志”);
}
@overide
Public void insert(){
saveLog();
System.out.println(“执行添加的业务需求”);
saveLog();
}
@overide
Public void update(){
saveLog();
System.out.println(“执行修改的业务需求”);
saveLog();
}
}
一般采用的继承策略。子类复写父类中需要增强的方法。然后程序直接调用子类这个方法。
1.2兄弟模式
Public interface Service{
Public void insert();
Public void update();
Public void delete();
Public void select();
}
Public class A_Class implements Service{
Public void insert(){
System.out.println(“执行添加的业务需求”);
}
Public void update(){
System.out.println(“执行修改的业务需求”);
}
Public void delete(){
System.out.println(“执行删除的业务需求”);
}
Public void select(){
System.out.println(“执行查询的业务需求”);
}
}
Public class B_Class implements Service{
Public void saveLog(){
System.out.println(“记录日志”);
}
Public void insert(){
saveLog();
System.out.println(“执行添加的业务需求”);
}
Public void update(){
saveLog();
System.out.println(“执行修改的业务需求”);
}
Public void delete(){
saveLog();
System.out.println(“执行删除的业务需求”);
}
Public void select(){
saveLog();
System.out.println(“执行查询的业务需求”);
}
}
AOP 思想: 基于代理思想,对原来目标对象,创建代理对象,在不修改原对象代码情况下,通过代理对象,调用增强功能的代码【系统需求方法】,从而对原有业务方法进行增强。
AOP的底层是动态代理机制【CGLIB动态代理】。
基于两种动态代理机制: JDK动态代理和CGLIB动态代理。
JDK动态代理:基于接口的代理,会生成目标对象的接口的子对象【实现接口的类】
CGLIB动态代理:基于类的代理,会生成目标对象的子对象。【无论是继承父类还是实现接口所产生的类】
1.通常情况下一个系统/软件的需求有2种:
业务需求:实现具体某一个业务逻辑功能的实现过程。【添加,删除,修改,查询等等】
系统需求:在整个系统运行的工程帮助完善系统业务需求的功能【性能监视,事务管理,安全检查,缓存,日志记录等】
2.如何完成将系统需求快速添加到具体的业务需求操作方法中,并且要在不修改原始代码的情况下可以随时移除系统需求?
解决上面的问题的做法就是使用代理模式设计自己的程序。
3.常见的代理模式,以及适合的代理模式。
3.1传统纵向继承体系【静态代理】—但是他在完成的代码设计的时候,会重复编写业务处理方法中的代码。
3.2横向抽取机制【动态代理】—创建一个类,由这个类为目标对象创建出代理对象。
3.2.1JDK动态代理 – jdk提供的InvocationHandler 和 Proxy 完成代理对象的创建。 — 但是他只能完成实现接口的子类的代理对象的创建。
3.2.2CGLIB 动态代理 – 使用cglib这个第三方的开发包, 完成代理对象的创建。可以为任何类提供出代理对象。
CGLIB 动态代理成为 AOP 的底层操作。
Spring 中的AOP,实际上是对CGLIB 动态代理的进一步的封装和应用。
我们学习AOP,要重点掌握,Spring封装好的Aop的操作类库的调用和配置,完成系统需求的快速植入和移除。
2.横向抽取机制【动态代理】
方法的调用依然不变。正常的去书写业务逻辑。只是在调用某个方法的时候会被AOP技术拦截。拦截之后就可以进行各种判断,业务编写,最后到底是否执行真正的功能,根据业务逻辑,最终可以使用反射的技术让被调用的方法运行。
15.AOP相关的概念
joinpoint(连接点):指那些被拦截到的点。在spring中指的可以被代理(增强)的方法。【业务类中的业务需求方法】
poingcut(切入点):对哪些连接点进行拦截的定义。在Spring中指的真正需要被代理(增强)的方法。
advice(通知/增强):指拦截到连接点之后要做的事情。真正增强的那些代码(逻辑)。
通知/增强分为:
前置通知,后置通知,异常通知,最终通知,环绕通知。
aspect(切面):是切入点和通知/增强的结合过程。
introduction(引介):一种特殊的通知在不修改类代码的前提下,introduction可以在运行期为类动态地添加一些方法或者字段。
target(目标对象):代码的目标对象。
weaving(织入):把增强应用到目标对象来创建新的代理对象的过程。spring采用动态代理织入。而AspectJ采用编译期织入和类装在期织入。
proxy(代理):一个类被AOP织入增强后,就产生一个结果代理类。
16.基于XML文件的AOP实现
4.基于XML文件的AOP实现
1.添加支持AOP的相关依赖
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.click369.springaop</groupId>
<artifactId>SpringAOPDemo1</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencies>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context-support -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-aspects -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/aopalliance/aopalliance -->
<dependency>
<groupId>aopalliance</groupId>
<artifactId>aopalliance</artifactId>
<version>1.0</version>
</dependency>
</dependencies>
<!-- 配置插件 -->
<build>
<plugins>
<!-- 配置jdk1.8的编译插件 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.2</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</build>
</project>
2.创建业务需求类,提供业务方法
package com.click369.service;
/**
* 业务访问接口
* @author Administrator
*
*/
public interface UserService {
void insertService();
void updateService();
void deleteService();
void selectService();
}
package com.click369.service.impl;
import com.click369.service.UserService;
/**
* 业务接口实现类
* @author Administrator
*
*/
public class UserServiceImpl implements UserService {
/**
* 添加的业务方法
*/
@Override
public void insertService() {
System.out.println("实现具体的添加操作");
}
/**
* 修改的业务方法
*/
@Override
public void updateService() {
System.out.println("实现具体的修改操作");
}
/**
* 删除的业务方法
*/
@Override
public void deleteService() {
System.out.println("实现具体的删除操作");
}
/**
* 查询的业务方法
*/
@Override
public void selectService() {
System.out.println("实现具体的查询操作");
}
}
3.编写一个系统需求类,统一管理系统需求方法。
package com.click369.avice;
import org.aspectj.lang.ProceedingJoinPoint;
/**
* 系统需求类[增强类]
* @author Administrator
*
*/
public class MyAvice {
/**
* 记录系统运行日志的系统需求方法
*/
public void savaLog(){
System.out.println("记录系统运行日志的系统需求方法");
}
/**
* 执行环绕通知的方法
*/
public void around( ProceedingJoinPoint joinPoint ) throws Throwable{
savaLog();
joinPoint.proceed(); // 调用真正的逻辑方法
savaLog();
}
}
4.配置Spring配置文件实现AOP
4.1导入aop命名空间地址
xmlns:aop="http://www.springframework.org/schema/aop"
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
<?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
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 创建业务需求类的对象【UserService接口对象】 -->
<bean id="userService" class="com.click369.service.impl.UserServiceImpl"></bean>
<!-- 创建系统需求类对象 [MyAvice类对象]-->
<bean id="myAvice" class="com.click369.avice.MyAvice"></bean>
<!-- 配置基于XML的aop实现 -->
<!-- aop:pointcut切入点配置元素 -->
<!-- expression:切入点表达式 -->
<!-- 格式:execution(<访问修饰符>?<返回类型>空格<方法名>(<参数>)<异常>?) -->
<!-- id:切入点的名称 -->
<!-- aop:aspect切面元素配置【切入点与通知的结合体】 -->
<!-- ref:系统需求类对象的引用 -->
<!-- aop:before前置通知配置元素 method:系统需求功能方法 pointcut-ref:切入点引用-->
<!-- aop:after-returning后置通知配置元素 method:系统需求功能方法 pointcut-ref:切入点引用-->
<!-- aop:after最终通知配置元素 method:系统需求功能方法 pointcut-ref:切入点引用-->
<!-- aop:around环绕通知配置元素 method:系统需求功能方法【系统需求类中单独定义】 pointcut-ref:切入点引用 -->
<!-- aop:after-throwing异常通知配置元素 method:系统需求功能方法 pointcut-ref:切入点引用 -->
<aop:config>
<aop:pointcut expression="execution(* com.click369.service.impl.UserServiceImpl.insertService(..))"
id="point1"/>
<aop:pointcut expression="execution(* com.click369.service.impl.UserServiceImpl.updateService(..))"
id="point2"/>
<aop:pointcut expression="execution(* com.click369.service.impl.UserServiceImpl.deleteService(..))"
id="point3"/>
<aop:aspect ref="myAvice">
<aop:before method="savaLog" pointcut-ref="point1"/>
<aop:after-returning method="savaLog" pointcut-ref="point2"/>
<aop:around method="around" pointcut-ref="point3"/>
</aop:aspect>
</aop:config>
</beans>
测试:
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
// 获取UserDao
UserService service = (UserService) context.getBean("userService");
service.insertService();
下面给出一些通用切入点表达式的例子。
1.任意公共方法的执行:
execution(public * (…))
2.任何一个名字以“set”开始的方法的执行:
execution( set*(…))
3.AccountService接口定义的任意方法的执行:
execution(* com.xyz.service.AccountService.(…))
4.在service包中定义的任意方法的执行:
execution( com.xyz.service..(…))
5.在service包或其子包中定义的任意方法的执行:
execution(* com.xyz.service….(…))
6.在service包中的任意连接点(在Spring AOP中只是方法执行):
within(com.xyz.service.)
7.在service包或其子包中的任意连接点(在Spring AOP中只是方法执行):
within(com.xyz.service…)
8.实现了AccountService接口的代理对象的任意连接点 (在Spring AOP中只是方法执行):
this(com.xyz.service.AccountService)
'this’在绑定表单中更加常用:- 请参见后面的通知一节中了解如何使得代理对象在通知体内可用。
9.实现AccountService接口的目标对象的任意连接点 (在Spring AOP中只是方法执行):
target(com.xyz.service.AccountService)
'target’在绑定表单中更加常用:- 请参见后面的通知一节中了解如何使得目标对象在通知体内可用。
10.任何一个只接受一个参数,并且运行时所传入的参数是Serializable 接口的连接点(在Spring AOP中只是方法执行)
args(java.io.Serializable)
'args’在绑定表单中更加常用:- 请参见后面的通知一节中了解如何使得方法参数在通知体内可用。
请注意在例子中给出的切入点不同于 execution(* *(java.io.Serializable)): args版本只有在动态运行时候传入参数是Serializable时才匹配,而execution版本在方法签名中声明只有一个 Serializable类型的参数时候匹配。
11.目标对象中有一个 @Transactional 注解的任意连接点 (在Spring AOP中只是方法执行)
@target(org.springframework.transaction.annotation.Transactional)
'@target’在绑定表单中更加常用:- 请参见后面的通知一节中了解如何使得注解对象在通知体内可用。
12.任何一个目标对象声明的类型有一个 @Transactional 注解的连接点 (在Spring AOP中只是方法执行):
@within(org.springframework.transaction.annotation.Transactional)
'@within’在绑定表单中更加常用:- 请参见后面的通知一节中了解如何使得注解对象在通知体内可用。
13.任何一个执行的方法有一个 @Transactional 注解的连接点 (在Spring AOP中只是方法执行)
@annotation(org.springframework.transaction.annotation.Transactional)
'@annotation’在绑定表单中更加常用:- 请参见后面的通知一节中了解如何使得注解对象在通知体内可用。
14.任何一个只接受一个参数,并且运行时所传入的参数类型具有@Classified 注解的连接点(在Spring AOP中只是方法执行)
@args(com.xyz.security.Classified)
‘@args’在绑定表单中更加常用:- 请参见后面的通知一节中了解如何使得注解对象在通知体内可用。
15任何一个在名为’tradeService’的Spring bean之上的连接点 (在Spring AOP中只是方法执行):
bean(tradeService)
16.任何一个在名字匹配通配符表达式’*Service’的Spring bean之上的连接点 (在Spring AOP中只是方法执行):
bean(*Service)
17.基于注解的Aop实现
5.基于注解的Aop实现
1.添加支持AOP的相关依赖
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.click369.springaop</groupId>
<artifactId>SpringAOPDemo1</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencies>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context-support -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-aspects -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/aopalliance/aopalliance -->
<dependency>
<groupId>aopalliance</groupId>
<artifactId>aopalliance</artifactId>
<version>1.0</version>
</dependency>
</dependencies>
<!-- 配置插件 -->
<build>
<plugins>
<!-- 配置jdk1.8的编译插件 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.2</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</build>
</project>
2.创建业务需求类,提供业务方法,在业务需求类上添加@Service,标注这个类是一个业务操作类。
/**
* 业务接口实现类
* @author Administrator
*
*/
@Service("userService")
public class UserServiceImpl implements UserService {
3.编写一个系统需求类,统一管理系统需求方法。
在系统需求类上添加@Component,通知Spring容器实例化系统需求类对象。
在系统需求类上添加@Aspect,表示这个系统需求类是一个切面类。
/**
* 系统需求类[增强类]
* @author Administrator
*
*/
@Component
@Aspect
public class MyAvice {
18.切入点表达式
.在系统需求类的,系统需求方法上通过注解配置切入点。
/**
* 记录系统运行日志的系统需求方法
*/
//@Before("execution(* com.click369.service.impl.UserServiceImpl.insertService(..))")
@AfterReturning("execution(* com.click369.service.impl.UserServiceImpl.updateService(..))")
public void savaLog(){
System.out.println("记录系统运行日志的系统需求方法");
}
/**
* 执行环绕通知的方法
*/
@Around("execution(* com.click369.service.impl.UserServiceImpl.deleteService(..))")
public void around( ProceedingJoinPoint joinPoint ) throws Throwable{
savaLog();
joinPoint.proceed(); // 调用真正的逻辑方法
savaLog();
}
5.在Spring的配置文件中,开启注解功能,和配置自动扫描包
<?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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
<!-- 开启注解 -->
<context:annotation-config />
<!-- 配置扫描包 -->
<context:component-scan base-package="com.click369.*" />
<!-- 开启aop注解 -->
<aop:aspectj-autoproxy />
</beans>
6.测试
@Test
public void test1()throws Exception{
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
// 获取UserDao
UserService service = (UserService) context.getBean("userService");
//service.insertService();
//service.updateService();
service.deleteService();
}
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200730171408844.png)
19.什么事务?
对数据库的一系列操作中,保证同时成功或者同时失败。不能出现成部分成功,失败部分的情况。而这一些列操作称为数据库的事务。
20.数据库的事务有4大特征【ACID】
数据库的事务有4大特征:
原子性:指事务是一个不可分割的工作单位,事务的操作要么都发生,要么都不发生.
一致性:事务前后数据的完整性必须保持一致。
隔离性:指多个用户并发访问数据库时,一个用户的事务不能被其他用户的事务干扰,多个并发之间的数据要相互隔离。
持久性:指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其又任何影响。简称ACID。其中隔离性最重要。
21.事务的隔离性
如果不考虑隔离性,可能会引发如下问题:
脏读:只一个事务读取到了另一个事务未提交的数据。
不可重复读:在一个事务内读取表中某一行数据,多次读取结果不同(一个事务读取到的另外一个事务提交的数据)
虚读(幻读):时指一个事务内读取到了别的事务插入的数据,导致前后读取不一致。
使用Java操作的时候设置隔离级别由高到低分别为:
Serializable:可避免脏读、不可重复读、虚读情况的发生。
Repeatable read:可避免脏读、不可重复读情况发生。(可重复读)
Read committed:可避免脏读情况的发生。(读已提交)
Read uncommitted:最低级别,以上情况均为无法保证。(读未提交)
值得一提的是:大多数数据库默认的事务隔离级别是Read committed,比如Sql Server , Oracle。Mysql的默认隔离级别是Repeatable read。
22.Spring的声明式事务管理方式
在Java中,可以通过Connection对象来设置数据库的隔离级别,以及控制事务。
Connection中支持的设置隔离级别的常量:
设置数据库的隔离级别:
Connection conn=DBConnection.getConnection();
//设置事物的隔离级别
conn.setTransactionIsolation(Connection.TRANSANCTION_READ_COMMITTED);
获取数据库的隔离级别:
控制事务:
1、在操作数据库之前,先取消数据库的自动提交:
2、当数据库出现问题的时候,回滚事务
3、当数据库操作一切都正常,提交事务
5.Spring的事务管理器
Spring提供的事务控制的接口:PlatformTransactionManager其中提供了三个方法:
根据dao层(持久层)使用的不同的框架,PlatformTransactionManager 的主要实现类大致如下:
DataSourceTransactionManager:适用于使用JDBC和MyBatis进行数据持久化操作的情况。
HibernateTransactionManager:适用于使用Hibernate进行数据持久化操作的情况。
JpaTransactionManager:适用于使用JPA进行数据持久化操作的情况。
另外还有JtaTransactionManager 、JdoTransactionManager、JmsTransactionManager等等
6.基于xml方式的事物管理操作
数据库中创建t_account账户表,模拟转账,演示spring的事务控制。
create table t_account(
account_id int primary key auto_increment,
user_name varchar(20),
money int
);
insert into t_account values(null,'刘能',10000);
insert into t_account values(null,'赵四',10000);
Spring+MyBatis工程结构
1.创建工程导入依赖
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.click369.springaop</groupId>
<artifactId>SpringAOPDemo1</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencies>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context-support -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-aspects -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/aopalliance/aopalliance -->
<dependency>
<groupId>aopalliance</groupId>
<artifactId>aopalliance</artifactId>
<version>1.0</version>
</dependency>
<!-- spring_tx -->
<!-- https://mvnrepository.com/artifact/org.springframework/spring-tx -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<!-- spring-jdbc -->
<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<!-- MyBatis依赖 -->
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.6</version>
</dependency>
<!-- mybatis-spring 整合包 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.1</version>
</dependency>
<!--druid 阿里的连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.7</version>
</dependency>
<!-- mysql数据库驱动 -->
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.38</version>
</dependency>
</dependencies>
<!-- 配置插件 -->
<build>
<plugins>
<!-- 配置jdk1.8的编译插件 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.2</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</build>
</project>
2.转账接口
package com.click369.mapper;
import java.util.Map;
/**
* 转账接口
* @author Administrator
*
*/
public interface TransferMapper {
// 加钱
public void addMoney(Map param);
// 减钱
public void lessMoney(Map param);
}
3.在src/main/resources下创建mapper文件夹,mapper文件夹中创建Sql映射文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.click369.mapper.TransferMapper">
<!-- 编写加钱的sql -->
<update id="addMoney" parameterType="hashMap">
update t_account set money = money + #{number} where user_name = #{username}
</update>
<!-- 编写减钱的sql -->
<update id="lessMoney" parameterType="hashMap">
update t_account set money = money - #{number} where user_name = #{username}
</update>
</mapper>
4.创建业务访问接口以及实现类
package com.click369.service;
/**
* 转账业务访问接口
* @author Administrator
*
*/
public interface TransferService {
/**
* 转账方法
* @throws Exception
*/
void transfer()throws Exception;
}
package com.click369.service.impl;
import java.util.HashMap;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.click369.mapper.TransferMapper;
import com.click369.service.TransferService;
/**
* 转账业务实现类
* @author Administrator
*
*/
@Service("transferService")
public class TransferServiceImpl implements TransferService {
//定义依赖对象
@Autowired
private TransferMapper transferMapper;
@Override
public void transfer() throws Exception {
//从刘能的账户减少1000元,给赵四的账户增加1000元
Map param1=new HashMap();
param1.put("number", 1000);
param1.put("username", "刘能");
transferMapper.lessMoney(param1);
//int i=10/0;
Map param2=new HashMap();
param2.put("number", 1000);
param2.put("username", "赵四");
transferMapper.addMoney(param2);
}
}
5.创建数据库链接资源
mydriver = com.mysql.jdbc.Driver
myurl = jdbc:mysql://127.0.0.1:3306/test
myusername = root
mypassword = 123456
6.配置Spring配置文件
<?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:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<!-- 读取数据库链接字符串的资源文件 -->
<context:property-placeholder location="classpath:mydatabase.properties"/>
<!-- 配置数据源 com.alibaba.druid.pool.DruidDataSource -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${mydriver}"></property>
<property name="url" value="${myurl}"></property>
<property name="username" value="${myusername}"></property>
<property name="password" value="${mypassword}"></property>
</bean>
<!-- 配置SqlSessionFactory "org.mybatis.spring.SqlSessionFactoryBean" -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="mapperLocations" value="classpath:mapper/*Mapper.xml"></property>
</bean>
<!--扫描所有Mapper接口-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.click369.mapper"/>
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
</bean>
<!-- 配置spring的事务管理 -->
<!-- 1.创建事务管理器对象-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- 需要配置数据源 -->
<property name="dataSource" ref="dataSource" />
</bean>
<!-- 2.创建事务-->
<!--id:事务名称 -->
<!--transaction-manager:事务管理器对象-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!-- 使用method配置是事务控制的方法,method的其他属性默认即可 -->
<tx:method name="transfer"/>
</tx:attributes>
</tx:advice>
<!-- 3.通过aop将上面创建好的事物,作用到指定的业务方法中 -->
<aop:config>
<aop:pointcut expression="execution(* com.click369.service.impl.TransferServiceImpl.transfer(..))" id="point1"/>
<!-- aop:advisor专门配置事务对象 -->
<aop:advisor advice-ref="txAdvice" pointcut-ref="point1"/>
</aop:config>
<!-- 开启Spring主解 -->
<context:annotation-config></context:annotation-config>
<!-- 配置扫描包 -->
<context:component-scan base-package="com.click369.service.impl"></context:component-scan>
</beans>
7.测试代码
ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");
TransferService transferService=(TransferService)ac.getBean("transferService");
transferService.transfer();
7.基于注解方式的事物管理操作
1.在需要管理事务的方法或者类上面 添加@Transactional 注解
package com.click369.service.impl;
import java.util.HashMap;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.click369.mapper.TransferMapper;
import com.click369.service.TransferService;
/**
* 转账业务实现类
* @author Administrator
*
*/
@Service("transferService")
//使用@Transactional注解来表示当前的类需要被spring的事务管理
@Transactional
public class TransferServiceImpl implements TransferService {
//定义依赖对象
@Autowired
private TransferMapper transferMapper;
@Override
public void transfer() throws Exception {
// 从刘能的账户减少1000元,给赵四的账户增加1000元
Map param1=new HashMap();
param1.put("number", 1000);
param1.put("username", "刘能");
transferMapper.lessMoney(param1);
int i=10/0;
Map param2=new HashMap();
param2.put("number", 1000);
param2.put("username", "赵四");
transferMapper.addMoney(param2);
}
}
2.配置注解驱动事务管理(事务管理注解生效的作用)(需要配置对特定持久层框架使用的事务管理器)
<?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:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<!-- 读取数据库链接字符串的资源文件 -->
<context:property-placeholder location="classpath:mydatabase.properties"/>
<!-- 配置数据源 com.alibaba.druid.pool.DruidDataSource -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${mydriver}"></property>
<property name="url" value="${myurl}"></property>
<property name="username" value="${myusername}"></property>
<property name="password" value="${mypassword}"></property>
</bean>
<!-- 配置SqlSessionFactory "org.mybatis.spring.SqlSessionFactoryBean" -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="mapperLocations" value="classpath:mapper/*Mapper.xml"></property>
</bean>
<!--扫描所有Mapper接口-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.click369.mapper"/>
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
</bean>
<!-- 开启Spring主键 -->
<context:annotation-config></context:annotation-config>
<!-- 配置扫描包 -->
<context:component-scan base-package="com.click369.service.impl"></context:component-scan>
<!-- 配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- 需要配置数据源 -->
<property name="dataSource" ref="dataSource" />
</bean>
<!-- 开启事务注解 -->
<!-- <tx:annotation-driven transaction-manager="transactionManager"/>-->
<!-- 默认会找transactionManager为名称的事务管理类对应的bean,
因此可以在配置tx:annotation-driven的时候省略transaction-manager属性 -->
<tx:annotation-driven/>
</beans>
3.测试:
ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");
TransferService transferService=(TransferService)ac.getBean("transferService");
transferService.transfer();
成功转账:
转账失败,事务回滚