Spring详解
1、Spring简介
核心
控制反转和面向切面的的容器
Spring 的理念
使现在的技术更加容易的使用,本身类似于一个大杂烩,整合了现在现有的技术框架!
官网:https://spring.io/
官方下载地址:
2、spring所需要的maven依赖
<!-- Spring核心依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>
<!-- Spring dao依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>
<!-- Spring web依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>
<!-- Spring test依赖:方便做单元测试和集成测试 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>
可以单独导入一下的maven依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.12</version>
</dependency>
<!-- 进行数据库的连接 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>
2.1、Spring的优点
- 是一个开源的免费的框架
- 是一个轻量级的、非入侵式的框架
- 控制反转(IOC)
- 面向切面编程(AOP)
- 支持事务的处理
- 对框架整合的支持
总结是一个轻量级的控制反转和面向切面的编程
2.2、Spring的组成
2.3、扩展
Spring现代化的Java开发
SpringBoot
- 快速开发的脚手架
- 基于SpringBoot可以开发单个微服务
- 约定大于配置类似于maven
SpringCloud
- 基于SpringBoot的实现
注:学习SpringBoot的前提是学习Spring与SpringMVC,承上启下
缺点
发展的时间太长,配置十分的繁琐
3、IOC理论推导
其内部代码通过set注入使得代码的主动权交给用户,进行代码主动性的
IOC本质
控制反转IOC是一种设计思想,DI(依赖注入)是实现IOC的一种方法,也有人认为DI只是IOC的另一种说法,没有IoC程序中,我们使用面向对象编程,对象的创建与对象间的依赖关系完全硬编程中,对象的创建由程序自己控制,控制反转后将对象的创建转移给第三方,个人认为所谓的控制反转就是获得依赖对象的方式反转了。
控制反转是一种通过(XML或注解)并通过第三方去生产或获取特定对象的方式。在Spring中实现控制反转的是IOC容器,其实现方法是依赖注入。
3.1、hello Spring
package com.li.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 version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 设置bean,通过Spring框架自动创建new对象-->
<bean id="getUser" class="com.li.pojo.Hello">
<!-- 对对象中的属性赋值,name表示对象中的属性的名称,value表示属性的值-->
<property name="str" value="Spring"/>
</bean>
</beans>
package com.li.test;
import com.li.pojo.Hello;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
//实现类
public class getUserTest {
public static void main(String[] args) {
// 进行文件的读取
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext .xml");
// 通过getBean方法获取对象,从而省略new
Hello getUser = (Hello) context.getBean("getUser");
System.out.println(getUser.toString());
}
}
例二
//创建接口
public interface getUser {
void getUserInformation();
}
//第一个实现类
package com.li.dao;
public class getUserImpl implements getUser {
@Override
public void getUserInformation() {
System.out.println("这是第一个句子");
}
}
//第二个实现类
package com.li.dao;
public class getUserImpl2 implements getUser{
@Override
public void getUserInformation() {
System.out.println("这是第二个句子");
}
}
//第三个实现类
package com.li.dao;
public class getUserImpl3 implements getUser{
@Override
public void getUserInformation() {
System.out.println("这是第三个句子");
}
}
//创建service接口
package com.li.service;
public interface getUserService {
void getUser();
}
//创建service的实现类
package com.li.service;
import com.li.dao.getUser;
import com.li.dao.getUserImpl;
public class getUserServiceImpl implements getUserService{
private getUser getUser;
public com.li.dao.getUser getGetUser() {
return getUser;
}
public void setGetUser(com.li.dao.getUser getUser) {
this.getUser = getUser;
}
@Override
public void getUser() {
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="getUserImpl1" class="com.li.dao.getUserImpl"/>
<bean id="getUserImpl2" class="com.li.dao.getUserImpl2"/>
<bean id="getUserImpl3" class="com.li.dao.getUserImpl3"/>
<bean id="getTest" class="com.li.service.getUserServiceImpl" >
<property name="getUser" ref="getUserImpl1"/>
</bean>
</beans>
<!--进行bean的配置-->
进行测试
package com.li.test;
import com.li.service.getUserServiceImpl;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class getUserTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext .xml");
getUserServiceImpl getUser = (getUserServiceImpl) context.getBean("getTest");
com.li.dao.getUser getUser1 = getUser.getGetUser();
getUser1.getUserInformation();
}
}
4、IoC创建对象的方式
-
使用无参构造创建对象(默认的方法)
-
进行有参构造方法创建(当创建有参的构造方法的时候,会把无参构造方法覆盖)
直接通过参数的名字进行创建
<!--通过constructor-arg为有参构造方法中的参数进行赋值--> <bean id="getTestDemo" class="com.li.pojo.testDemo"> <constructor-arg name="str" value="你好世界"/> </bean>
通过下标进行创建
<bean id="getTestDemo01" class="com.li.pojo.testDemo"> <constructor-arg index="0" value="你好世界1"/> <constructor-arg index="1" value="12"/> </bean>
5、Spring的配置
5.1、别名
alias
通过此属性对Spring中的实例化对象进行重命名、
5.2、Bean的配置
- id:id表示bean中的唯一的标识符,也相当于我们现在所说的对象名
- class:bean对象中所对应的全限定名:包名加类型
- name:name也是别名,而且那么可以同时取多个别名多个名字之间通过逗号进行分割
5.3、import
一般用于团队开发使用,它可以将多个配置文件导入并配置为一个
假设当只三个人进行开发的时候,import可以将三个任缩写的Spring中的xml文件进行汇总,到最后的时候只采用一个总的文件
6、DI依赖注入
6.1、构造器注入
通过常见的有参构造或者是无参构造进行注入
6.2、set方式注入【重点】
-
依赖注入:本质是set注入
- 依赖:bean对象的创建依赖于容器(Spring)
- 注入:bean对象的所有属性由容器注入
package com.li.pojo; import java.util.*; public class Student { private String name; private Address address; private String[] books; private List<String> hobby; private Map<String,String> card; private Set<String> games; private String wife; private Properties info; //表示用户的信息 public String getName() { return name; } public void setName(String name) { this.name = name; } public Address getAddress() { return address; } public void setAddress(Address address) { this.address = address; } public String[] getBooks() { return books; } public void setBooks(String[] books) { this.books = books; } public List<String> getHobby() { return hobby; } public void setHobby(List<String> hobby) { this.hobby = hobby; } public Map<String, String> getCard() { return card; } public void setCard(Map<String, String> card) { this.card = card; } public Set<String> getGames() { return games; } public void setGames(Set<String> games) { this.games = games; } public String getWife() { return wife; } public void setWife(String wife) { this.wife = wife; } public Properties getInfo() { return info; } public void setInfo(Properties info) { this.info = info; } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", address=" + address.toString() + ", books=" + Arrays.toString(books) + ", hobby=" + hobby + ", card=" + card + ", games=" + games + ", wife='" + wife + '\'' + ", info=" + info + '}'; } }
package com.li.pojo; public class Address { private String address; public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } @Override public String toString() { return "Address{" + "address='" + address + '\'' + '}'; } }
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="getAddress" class="com.li.pojo.Address"> <property name="address" value="山东省济南市"/> </bean> <bean id="getStudent" class="com.li.pojo.Student"> <property name="name" value="小明"/> <property name="address" ref="getAddress"/> <!-- 对数组进行值的注入--> <property name="books"> <array> <value>水浒传</value> <value>西游记</value> <value>红楼梦</value> <value>三国演义</value> </array> </property> <property name="hobby"> <list> <value>唱歌</value> <value>打游戏</value> <value>写代码</value> </list> </property> <property name="card"> <map> <entry key="身份证" value="37089932165872"/> <entry key="学生证" value="78236456055"/> </map> </property> <property name="games"> <set> <value>英雄联盟</value> <value>王者荣耀</value> <value>吃鸡</value> </set> </property> <property name="wife" value=""/> <property name="info"> <props> <prop key="地址">山东省济南市</prop> </props> </property> </bean> </beans>
测试
package com.li.test; import com.li.pojo.Student; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class getStudentDemo { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext .xml"); Student getStudent = (Student) context.getBean("getStudent"); System.out.println(getStudent.toString()); } }
6.3、其他方式
p命名方式
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close"
p:driverClassName="com.mysql.jdbc.Driver"
p:url="jdbc:mysql://localhost:3306/mydb"
p:username="root"
p:password="misterkaoli"/>
</beans>
c命名方式
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:c="http://www.springframework.org/schema/c"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="beanTwo" class="x.y.ThingTwo"/>
<bean id="beanThree" class="x.y.ThingThree"/>
<!-- traditional declaration with optional argument names -->
<bean id="beanOne" class="x.y.ThingOne">
<constructor-arg name="thingTwo" ref="beanTwo"/>
<constructor-arg name="thingThree" ref="beanThree"/>
<constructor-arg name="email" value="something@somewhere.com"/>
</bean>
<!-- c-namespace declaration with argument names -->
<bean id="beanOne" class="x.y.ThingOne" c:thingTwo-ref="beanTwo"
c:thingThree-ref="beanThree" c:email="something@somewhere.com"/>
</beans>
注:p命名方式与c命名方式需要导入xml文件的约束
6.4、Bean的作用域
-
单例模式(spring的默认机制)(单线程使用单例模式)
表示这个bean唯一
<bean id="getAddress" class="com.li.pojo.Address" scope="singleton"> <property name="address" value="山东省济南市"/> </bean>
-
原型模型:每次从容器中get的时候,都会产生一个新的对象(多线程使用原型模型)
<bean id="getAddress" class="com.li.pojo.Address" scope="prototype"> <property name="address" value="山东省济南市"/> </bean>
表示这个bean不是唯一的
-
其余的request、session、application
7、Bean的自动装配
- 自动装配是Spring满足bean依赖的一种方式
- Spring会在上下文中自动寻找,并自动给bean装配属性
在Spring中的三种装配的方式
- 在xml中显示配置
- 在java中显示配置
- 隐式的自动装配bean(重点)
7.1、autowire自动装配
package com.li.pojo;
public class People {
private String peopleName;
private Cat cat;
private Dog dog;
public String getPeopleName() {
return peopleName;
}
public void setPeopleName(String peopleName) {
this.peopleName = peopleName;
}
public Cat getCat() {
return cat;
}
public void setCat(Cat cat) {
this.cat = cat;
}
public Dog getDog() {
return dog;
}
public void setDog(Dog dog) {
this.dog = dog;
}
@Override
public String toString() {
return "People{" +
"peopleName='" + peopleName + '\'' +
", cat=" + cat.toString() +
", dog=" + dog.toString() +
'}';
}
}
byName
原理:会自动在容器的上下文进行寻找,和自己set方法后面值对应的beanid
<bean id="dog" class="com.li.pojo.Dog">
<property name="dogName" value="小黑"/>
</bean>
<bean id="cat" class="com.li.pojo.Cat">
<property name="name" value="小花"/>
</bean>
<bean id="getPeopleName" class="com.li.pojo.People" autowire="byName">
<property name="peopleName" value="小明"/>
</bean>
byType
原理:会自动的在容器的上下文进行寻找,与自己对象属性类型相同的bean
<bean id="dog" class="com.li.pojo.Dog">
<property name="dogName" value="小黑"/>
</bean>
<bean id="cat111" class="com.li.pojo.Cat">
<property name="name" value="小花"/>
</bean>
<bean id="getPeopleName" class="com.li.pojo.People" autowire="byType">
<property name="peopleName" value="小明"/>
</bean>
小结:
- ByName的时候,需要保证素所有的bean的id唯一,并且这个bean需要和自动注入的属性的set方法一致
- byType的时候,需要保证所有的bean的类型唯一,并且这个bean的需要和自动注入的属性类型一样
7.2、使用注解实现自动装配
JDK1.5之后支持注解
注使用注解需要添加一些支持
-
导入约束
-
配置注解的支持
<?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
- 直接在属性上使用即可
- 在使用 @Autowired我们可以不用书写Set方法,前提是你这个自动装配的这个属性在IOC容器中存在,且符合咱们的名字byName
- 它可以对类成员变量、方法及构造函数进行标注,完成自动装配的工作。 通过 @Autowired的使用来消除 set ,get方法。在使用@Autowired之前,我们对一个bean配置起属性时,是这用用的
科普
@Nullable 字段名标记了这个注解,说明这个字段可以为空@Autowired(request=false)与@Nullable 的效果一样,就是允许其中的字段为空
@Qualifier
注:如果@Autowired自动装配的环境比较复杂,自动装配无法通过一个注解【@Autowired】完成的时候,我们可以使用@Qualifier(value=“xxx”)进行重命名,去配合@Autowired的使用
public class MovieRecommender { @Autowired @Qualifier("main") private MovieCatalog movieCatalog; // ... }
@Resource java自带的注解
其会先通过名字进行查找,在名字不符合的时候在去根据类型去查找
@Resource(name=“xxx”)通过name进行命名的改变,配合resource进行使用
小结
@Resource与@Autowrie的区别
- 都是用来进行子发动装配的,都可以放在属性的字段上
- @Autowrie通过byType的方式 进行实现,而且必须要求这个对象实现
- @Resource默认的是byname如果找不到会通过byType进行查找实现,如果两个都找不到的情况,程序便会报错
- 执行顺序不同,@Resource先通过byname的方式进行实现,但是@Autowrie是先通过byType的方式进行实现。
8、注解开发
注:在Spring中使用注解一定要导入AOP的依赖
谁知Spring扫描指定的包
-
bean的实现
<?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:component-scan base-package="cn.itcast" /> <context:annotation-config/> </beans>
-
属性的注入
package com.li.pojo; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; //表示对该类进行相关的扫描 //@Component类似于 <bean id="people" class="com.li.pojo.People"/> //其中的id名称默认为类名的小写 @Component public class People { // 对类中的属性进行赋值 // 类似于 <property name="name" value="李四"/> @Value("李四") private String name; public void getPeople(){ System.out.println(name); } }
xml文件的配置
<?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:component-scan base-package="com.li.pojo" /> <!-- 启动使用注解开发的驱动--> <context:annotation-config/> <bean id="people" class="com.li.pojo.People"/> </beans>
-
衍生注解
@Component有几个衍生的注解,我们在web的开发中,会按照mvc三层架构进行分层
-
dao【通过@Repository进行标注】
-
service【通过@Service进行标注】
-
controller【通过@Controller进行标注 】
这四个的注解功能是一样的,都是将某个类注册到我们的Spring的容器中进行bean的装配
-
-
自动装配
看7.2
-
作用域
@Scope,设置其为单例模式或者是原型模式
- 单例模式表示bean是唯一的
- 原型模式表示其为多种
-
小结
xml与注解:
- xml更加的万能,适用于任何的场合,维护更加的简单
- 注解:不是自己的类自己无法使用,维护更加的复杂
最佳实践:
- xml用来管理bean
- 注解只负责完成属性的注入;
- 我们在使用的过程中注意的问题,必须让注解生效,就需要开启注解的支持。
9、使用java的方式 配置Spring
10、代理模式
学习代理模式的原因:其为SpringAop的底层
面试的常见面试题【SpringAOP与SpringMVC】
- 静态代理
- 动态代理
10.1、静态代理
角色分析:
- 抽象角色:一般会使用接口或者是抽象类来解决
- 真是角色:被代理的角色
- 代理角色:代理真实角色,代理真实角色后,一般我们会做一些负附属的操作
- 客户:访问代理对象的人
代理模式的优点:
- 可以使真实角色的操作更加的简单纯粹,不用去关注一些公共的业务
- 公共也就就交给代理角色,实现业务的分工
- 恭送业务发生扩展的时候,方便集中管理
缺点:
- 一个真实的角色就会产生一个代理角色。代码量较大,效率较低
10.2、静态代理的在理解
日志的添加
10.3、动态代理
角色分析:
- 动态代理与静态代理的角色分析是相同的
- 动态代理的代理类是动态生成的
- 动态代理分为两大类
- 基于接口的动态代理(JDK的动态代理)
- 基于类的动态代理
- Java字节码实现:javasist
需要了解两个类:Proxy,InvocationHandler:调用处理程序
InvocationHandler
动态代理的好处
- 可以shi真实角色的操作更加的纯粹,不用去关注一些公共的业务
- 公共也就交给代理就角色,实现了业务上的分工
- 公共业务发生扩展的时候,方便集中管理
- 一个动态代理类代理的是一个接口,一般就是相应的一类业务。
- 一个动态代理类可以代理多个类 ,只要实现了同一个接口
11、AOP(面向切面编程)
11.1、简介
简介
面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
11.2、AOP在Spring中的作用
提供声明式事务,允许用户自定义切面
- 横切关注点:跨越应用程序多个模块的方法和功能,即是,与我们业务逻辑无关,但是我们需要关注的部分,就是横切关注点,如日志,安全,缓存,事务等等
- 切面(ASPECT):横切关注点被模块化的特殊对象。即,他是一个类
- 通知(Advice):切面必须要完成的工作,他是类中的一个方法
- 目标(Target):被通知的对象
- 代理(Proxy):向目标对象应用通知之后创建的对象
- 切入点(PointCut):切面通知执行的“地点”的定义
- 连接点 :与切入点匹配的执行点
Spring实现Aop所需要的maven依赖
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.8.RC1</version>
</dependency>
所需要的applicationContext.xml文件的配置
<?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">
</beans>
11.3、使用Spring实现AOP的编程
方式1(通过API接口)
测试接口
package com.li.Service;
public interface UserService {
void selectUserSevice();
void updateUserSevice();
void deleteUserSevice();
void insertUserSevice();
}
接口的实现类
package com.li.Service;
public class UserServiceImpl implements UserService {
@Override
public void selectUserSevice() {
System.out.println("用户进行查询");
}
@Override
public void updateUserSevice() {
System.out.println("用户进行信息修改");
}
@Override
public void deleteUserSevice() {
System.out.println("用户进行了信息的删除");
}
@Override
public void insertUserSevice() {
System.out.println("进行信息的插入");
}
}
扩展代理类(动态代理)
package com.li.Log;
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
public class log implements MethodBeforeAdvice {
/*
* method:要执行的目标对象的方法
* object:参数
* target:目标对象
* */
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println(target.getClass().getName()+"的"+method.getName()+"被执行");
}
}
package com.li.Log;
import org.springframework.aop.AfterReturningAdvice;
import java.lang.reflect.Method;
public class AfterLog implements AfterReturningAdvice {
@Override
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println("执行了"+method.getName()+"返回结果为"+returnValue);
}
}
applicationContext .xml
<?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="getUserService" class="com.li.Service.UserServiceImpl"/>
<bean id="log" class="com.li.Log.log"/>
<bean id="afterLog" class="com.li.Log.AfterLog"/>
<!-- 这是一个配置-->
<aop:config>
<!-- 这是一个切入点-->
<!-- expression:表达式 execution()执行的位置 -->
<aop:pointcut id="pointcut" expression="execution(* com.li.Service.UserServiceImpl.*(..))"/>
<!-- 执行环绕增加-->
<aop:advisor advice-ref="log" pointcut-ref="pointcut"/>
<aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>
</aop:config>
</beans>
实现类
package com.li.Test;
import com.li.Service.UserService;
import com.li.Service.UserServiceImpl;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext .xml");
// 动态代理代理的是接口
UserService getUserService = (UserService) context.getBean("getUserService");
getUserService.deleteUserSevice();
}
}
注:在动态代理中,其所代理的是接口,不是接口的实现类
11.4、自定义实现AOP
测试接口
package com.li.Service;
public interface UserService {
void selectUserSevice();
void updateUserSevice();
void deleteUserSevice();
void insertUserSevice();
}
接口的实现类
package com.li.Service;
public class UserServiceImpl implements UserService {
@Override
public void selectUserSevice() {
System.out.println("用户进行查询");
}
@Override
public void updateUserSevice() {
System.out.println("用户进行信息修改");
}
@Override
public void deleteUserSevice() {
System.out.println("用户进行了信息的删除");
}
@Override
public void insertUserSevice() {
System.out.println("进行信息的插入");
}
}
扩展代理类(动态代理)
package com.li.Log;
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
public class log implements MethodBeforeAdvice {
/*
* method:要执行的目标对象的方法
* object:参数
* target:目标对象
* */
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println(target.getClass().getName()+"的"+method.getName()+"被执行");
}
}
package com.li.Log;
import org.springframework.aop.AfterReturningAdvice;
import java.lang.reflect.Method;
public class AfterLog implements AfterReturningAdvice {
@Override
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println("执行了"+method.getName()+"返回结果为"+returnValue);
}
}
自定义切面
package com.li.Diy;
public class DiyPointcut {
public void before(){
System.out.println("方法执行之前");
}
public void after(){
System.out.println("方法执行之后");
}
}
applicationContext .xml
<?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="getUserService" class="com.li.Service.UserServiceImpl"/>
<bean id="log" class="com.li.Log.log"/>
<bean id="afterLog" class="com.li.Log.AfterLog"/>
<bean id="diy" class="com.li.Diy.DiyPointcut"/>
<aop:config>
<!-- 进行自定义切面-->
<aop:aspect ref="diy">
<!-- 切入点-->
<aop:pointcut id="pointcut" expression="execution(* com.li.Service.UserServiceImpl.*(..))"/>
<aop:before method="before" pointcut-ref="pointcut" />
<aop:after method="after" pointcut-ref="pointcut" />
</aop:aspect>
</aop:config>
</beans>
实现类
package com.li.Test;
import com.li.Service.UserService;
import com.li.Service.UserServiceImpl;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext .xml");
// 动态代理代理的是接口
UserService getUserService = (UserService) context.getBean("getUserService");
getUserService.deleteUserSevice();
}
}
注:在动态代理中,其所代理的是接口,不是接口的实现类
11.5、注解实现AOP
package com.li.Diy;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
//使用注解的方式实现AOP
//标注这个类是一个切面
@Aspect
public class AnnotationpointCut {
//在方法前面添加方法
@Before("execution(* com.li.Service.UserServiceImpl.*(..))")
public void before(){
System.out.println("方法执行之前11111");
}
// 在方法后面进行方法的添加
@After("execution(* com.li.Service.UserServiceImpl.*(..))")
public void after(){
System.out.println("在方法执行之后执行11111");
}
}
12、Spring与Mybatis的整合
版本要求
通过xml文件中进行整合(第一种整合方式)
Spring-dao.xml
<?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="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/lyj?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&useSSL=false"/>
<property name="username" value="root"/>
<property name="password" value=""/>
</bean>
<!-- 为sqlSessionFactory配置数源,并连接mybatis-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<!-- 绑定mybatis文件-->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
</bean>
<!-- 创建sqlSession的-->
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<!-- 在注册sqlSession的时候所采用的时构造方法的注入,因为在SqlSessionTemplate没有set方法-->
<constructor-arg ref="sqlSessionFactory" index="0"/>
</bean>
</beans>
applicationContext.xml
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<import resource="spring-dao.xml"/>
<bean id="usermapper1" class="com.li.mapper.UsermapperImpl">
<property name="sqlSession" ref="sqlSession"/>
</bean>
</beans>
Mybatis-config
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 包下的文件进行命名-->
<typeAliases>
<package name="com.li.pojo"/>
</typeAliases>
<!-- 扫描mapper文件下的xml文件-->
<mappers>
<mapper resource="com/li/mapper/UserMapper.xml"/>
</mappers>
</configuration>
poji类
package com.li.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.apache.ibatis.type.Alias;
@Alias("user")
@Data //提供set、get、与toString的方法
@AllArgsConstructor //创建有参构造
@NoArgsConstructor //创建无参构造
public class User {
private int uid;
private String uname;
private String usex;
}
UserMapper
package com.li.mapper;
import com.li.pojo.User;
import org.apache.ibatis.annotations.Param;
public interface UserMapper {
User testDemo(@Param("id") int id);
}
UserMapper.xml
<?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.li.mapper.UserMapper">
<select id="testDemo" parameterType="int" resultType="user">
SELECT * from lyj.`user` where uid=#{id}
</select>
</mapper>
UserMapperImpl
package com.li.mapper;
import com.li.pojo.User;
import org.mybatis.spring.SqlSessionTemplate;
public class UsermapperImpl implements UserMapper{
private SqlSessionTemplate sqlSession;
public void setSqlSession(SqlSessionTemplate sqlSession) {
this.sqlSession = sqlSession;
}
@Override
public User testDemo(int id) {
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User select = mapper.testDemo(id);
return select;
}
}
test
package com.li.test;
import com.li.mapper.UserMapper;
import com.li.mapper.UsermapperImpl;
import com.li.pojo.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class test {
@Test
public void test1(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext .xml");
UsermapperImpl userMapper = context.getBean("usermapper1", UsermapperImpl.class);
User select = userMapper.testDemo(1);
System.out.println(select.toString());
}
}
注:当Spring进行整合的时候,我们需要通过一个Mapper的实现类在Spring进行注册实体类,在进行测试过
第二种整合方式(SqlSessionDaoSupport)
SqlSessionDaoSupport
是一个抽象的支持类,用来为你提供 SqlSession
。调用 getSqlSession()
方法你会得到一个 SqlSessionTemplate
,之后可以用于执行 SQL 方法,就像下面这样:
UserMapperImpl
package com.li.mapper;
import com.li.pojo.User;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.support.SqlSessionDaoSupport;
public class UsermapperImpl extends SqlSessionDaoSupport implements UserMapper{
private SqlSessionTemplate sqlSession;
public void setSqlSession(SqlSessionTemplate sqlSession) {
this.sqlSession = sqlSession;
}
@Override
public User testDemo(int id) {
UserMapper mapper = getSqlSession().getMapper(UserMapper.class);
User user = mapper.testDemo(id);
return user;
}
}
Spring-dao
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<!--配置数据源-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/lyj?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&useSSL=false"/>
<property name="username" value="root"/>
<property name="password" value="lyj18366635303"/>
</bean>
<!-- 为sqlSessionFactory配置数源,并连接mybatis-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<!-- 绑定mybatis文件-->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
</bean>
<!-- 创建sqlSession的-->
</beans>
applicationContex.xml
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<import resource="spring-dao.xml"/>
<bean id="usermapper1" class="com.li.mapper.UsermapperImpl">
<property name="sqlSessionFactory" ref="sqlSessionFactory"/>
</bean>
</beans>
注,SqlSessionDaoSupport的实现只是通过SqlSessionDaoSupport中的getSqlSession()获取SqlSession,调用mybatis,其主要改变的是applicationContext.xml还有Spring-bao.xml还有UserMapperImpl
13、声明式事务
13.1、回顾事务
定义
- 把一组业务当成一个业务来做要么都成功,要么都失败
- 事务在开发中,十分的重要,涉及到数据的一致性问题,不能马虎
- 确保完整性和一致性;
事务的ACID原则
- 一致性
- 隔离性
- 多个业务操作同意个资源的时候,必须确保数据的安全
- 原子性
- 持久性
- 事务一旦提交,无论系统发生什么问题,书记都不会被影响,被持久化的存储
13.2、spring中的事务管理
- 声明式事务:AOP
- 编程式事务:需要在代码中那个进行,进行事务管理
声明事务时的xml文件中的配置
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<!-- 配置数据源-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/lyj?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&useSSL=false"/>
<property name="username" value="root"/>
<property name="password" value="lyj18366635303"/>
</bean>
<!-- 注册sql工场-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<!-- 绑定mybatis文件-->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
</bean>
<!-- 开启事务处理-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<constructor-arg 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="query" propagation="REQUIRED"/>
<tx:method name="update" propagation="REQUIRED"/>
<!-- 为所有的方法开启事务-->
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="pointCut" expression="execution(* com.li.mapper.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="pointCut"/>
</aop:config>
</beans>
为什么要使用事务
- 如果不配置事务,可能存在数据不一致的情况
- 如果我们不在Spring中配置声明事务,我们就需要在代码中手动的配置事务
- 事务在项目开发中非常的重要,设计数据的一致性和完整性的问题,不能省略
注:在查询数据的时候,在没有条件限制的时候,当一条数据的时候可以采用单独的实体类进行存储,但是当数据超过一条时,则需要List进行存储
name=“url” value=“jdbc:mysql://localhost:3306/lyj?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&useSSL=false”/>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<!-- 绑定mybatis文件-->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<constructor-arg 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="query" propagation="REQUIRED"/>
<tx:method name="update" propagation="REQUIRED"/>
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="pointCut" expression="execution(* com.li.mapper.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="pointCut"/>
</aop:config>
```
为什么要使用事务
- 如果不配置事务,可能存在数据不一致的情况
- 如果我们不在Spring中配置声明事务,我们就需要在代码中手动的配置事务
- 事务在项目开发中非常的重要,设计数据的一致性和完整性的问题,不能省略
注:在查询数据的时候,在没有条件限制的时候,当一条数据的时候可以采用单独的实体类进行存储,但是当数据超过一条时,则需要List进行存储