2020-11-24Spring框架笔记


1.spring框架的概述以及Spring中基于xml的ioc配置
2.spring中基于注解的ioc和ioc的案例
3.spring中的aop和基于xml以及注解的aop配置
4.spring中的JdbcTemlate以及Spring事务控制

Spring概述

什么是spring

Spring框架是由于软件开发的复杂性而创建的。Spring使用的是基本的JavaBean
来完成以前只可能由EJB完成的事情。然而,Spring的用途不仅仅限于服务器端
的开发。从简单性、可测试性和松耦合性角度而言,绝大部分Java应用都可以从
Spring中受益。
Spring分层的Java SE/EE应用 full-stack 轻量级开源框架,以IoC(Inverse Of Control)
反转控制和AOP(Aspect Rriented Programming:面向切面编程)微内核,提供了展
现层SpringMVC和持久层Spring JDBC 以及业务层事务管理等众多企业级应用技术,还整合了开源世界,
著名的众多第三方框架和类库,逐渐成为使用最多的Java EE企业应用开源框架

spring的两大核心

spring的发展历程和优势

2.优势
	1.方便解耦,简化开发
	2.AOP编程的支持
	3.方便程序的测试
	4.方便集成各种优秀框架
	5.Java源码是经典学习范例

spring的体系结构

Beans,Core,Context,SpEL

IOC

程序的耦合以及解耦(ioc)

耦合和解耦

1.出处
	耦合的耦,在中国古代是指 两人并肩而耕,就是两个人在一起合作使用农具耕地,这是上古农耕时代
	对农业生产的写实描述,是中古时代以前古中国的田园生活,(中国上古、中古)农具“耒”(犁的前身)
	是需要两个人一起进行合作,进行联合操作的。
2.自己的话
	用我自己的话来讲,耦合就是两种或多种东西存在着某种联系,当其中一个东西发生变化时,其他的东西
	也要配合着发生变化。
3.编程领域的耦合
	在编程界里,耦合是指两个或者多个程序块之间有存在某种联系,当一个程序快发生变化时,另一个
	程序块也要发生变化,当这种联系越大,另一个程序要改的就越多。当联系非常大时,他们就可以说成
	是一个程序块
4.如何看待耦合以及解耦的概念
	在编程领域,在进行程序的某个功能更新迭代时,我们当然不希望整个项目都跟着一起改动,这是一件非
	常令人头疼的事情。因此我们要降低程序的耦合性,使得我们的项目可以分成几个程序块的集合,而某个
	程序块又可以分成更小的程序块,他们之间耦合性很低。我们把降低程序耦合性的行为称为程序的解耦

曾经的案例

1.解耦
	1.Bean在计算机英语中,代表可重复组件的含义
	2.JavaBean:用java语言编写的可重复组件
		他就是创建我们的service和dao组件的类
	一、需要一个配置文件来配置我们的service和dao(可以是xml,或者properties )
		配置内容:唯一标识=全限定类名
	二、读取配置文件的内容,从而创建service和dao对象

工厂模式解耦

1.在java语言中的23种设计模式中的(工厂模式是)一种很好的针对我们在获取对象需要new然后写类名,这
种耦合现象的(解耦思想)
2.工厂模式是通过创建一个工厂对象,工厂对象根据提前设定好的配置文件来提前创建好所要用到的对象
当我们需要用某个对象的时候,通过对象在配置文件的唯一标识符和工厂即可获取所要的对象,这样我们
只需知道类的唯一标识符就能创建对象。
3.当我们更改了要获取的对象,而他们都实现(继承)了同一个
接口(类),我们只需更改配置文件中唯一标识符(key)的全限定类名(value)即可实现程序的更新。

IOC概念和spring中的ioc

1.中文名为控制反转
2.概念
	控制反转(Inversion of Contral)把创建对象的权力交给框架,是框架的重要特征,并非面向对象编程的专用术语。它包括依赖注入和依赖查找
3.作用:削减计算机程序间的耦合度(降低我们代码中的依赖关系)

spring中基于xml的ioc环境搭建

一、创建maven工程
二、导入spring的jar包
	dependency为:
		<dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>
    注意:此处存放资源的文件名不能有repository,建议改成repositories
三、配置xml文件
1. 导入xml文件的schema约束
	<?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">
2.配置文件中只需要我们要创建对象的唯一标识以及全限定类名,也就是bean的两个属性
	<bean id="唯一标识" class="全限定类名"></bean>
    例:<bean id="accountDao" class="com.itheima.dao.impl.AccountDaoImpl"></bean>
四、通过spring中的工厂创建对象
//1.获取核心容器对象
ApplicationContext applicationContext=new ClassPathXmlApplicationContext("bean.xml");
//2.根据对象的唯一标识来获取对象
//2.1自己强转
AccountService accountService=(AccountService) applicationContext.getBean("accountService");
//2.2人家给你强转
AccountDao accountDao = applicationContext.getBean("accountDao", AccountDao.class);

核心容器

1.两个核心容器接口引发的问题
	1.ApplicationContext      单例对象适用   //一般采用此接口
		构建核心容器时,采用立即加载的方式创建对象,只要读取完配置文件就创建配置文件中的对象
	2.BeanFactory	       多例对象或者是单例对象非常多以至于不能在短时间内创建完时适用
		构建核心容器时,采用延迟加载的方式创建对象,只有在根据id创建对象时才会创建对象
ApplicationContext核心容器的三个实现类:
	ClassPathXmlApplicationContext:可以加载类路径下的xml配置文件,要求xml配置文件必须在类路径下
	FileSystemXmlApplicationContext:可以加载任意路径的下的xml配置文件,但不建议使用
	AnnotationConfigApplicationContext:通过注解获取配置信息

spring容器对bean对象的管理细节

创建bean的三种方式(配置不同)
1.使用默认构造函数即无参构造函数创建对象
	spring在配置文件中使用bean标签,配以id和class属性后,没有其他属性和标签。
	采用的就是bean对象的默认构造函数,如果bean对象没有默认构造函数就会报错
	例子:<bean id=accountService class="com.itheima.service.impl.AccountServiceImpl"></bean>
2.使用工厂对象中的方法创建bean对象
	<bean id="instanceFactory" class="全限定类名"></bean>
	<bean id="accountService" factory-bean="instanceFactory" factory-method="方法名">
3.使用静态工厂的静态方法创建对象
	<bean id=accountService class="工厂全限定类名" factory-method="方法名"></bean>
bean的作用范围
1.种类
	1. singleton:单例的(默认值)
	2. prototype:多例的
	3. request:作用于web应用的请求范围
	4. session:作用于web应用的会话范围范围
	5. global-session:作用于集群环境的会话范围(全局会话范围),当不是集群环境是,他就是session
		集群环境:在一个访问量非常大的项目中,需要由多个服务器来共同工作,而它们之间需要数据共享,这个共享的范围就是global-session
2.设置:
	通过bean标签的scope属性设置
bean对象的生命周期
* 注意:spring中默认单例单例对象都是立即加载的,多例对象都是延迟加载的
1.单例对象
	出生:容器开启
	活着:容器活着
	死亡:容器关闭
2.多例
	出生:获取对象时
	活着:使用对象时
	死亡:垃圾回收器回收时

依赖注入(Dependency Injection)

依赖

java--依赖、关联、聚合和组合之间区别的理解  
在学习面向对象设计对象关系时,依赖、关联、聚合和组合这四种关系之间区别比较容易混淆。特别是后
三种,
仅仅是在语义上有所区别,所谓语义就是指上下文环境、特定情景等。 
依赖(Dependency)关系是类与类之间的联接。依赖关系表示一个类依赖于另一个类的定义。例如,一个人
(Person)可以买车(car)和房子(House),Person类依赖于Car类和House类的定义,因为Person类引用了Car
和House。与关联不同的是,Person类里并没有Car和House类型的属性,Car和House的实例是以参量的方
式传入到buy()方法中去的。一般而言,依赖关系在Java语言中体现为局域变量、方法的形参,或者对静态方
法的调用。 
关联(Association)关系是类与类之间的联接,它使一个类知道另一个类的属性和方法。关联可以是双向的,
也可以是单向的。在Java语言中,关联关系一般使用成员变量来实现。 

聚合(Aggregation) 关系是关联关系的一种,是强的关联关系。聚合是整体和个体之间的关系。例如,
汽车类与引擎类、轮胎类,以及其它的零件类之间的关系便整体和个体的关系。与关联关系一样,聚合关系也
是通过实例变量实现的。但是关联关系所涉及的两个类是处在同一层次上的,而在聚合关系中,两个类是处在
不平等层次上的,一个代表整体,另一个代表部分。 

组合(Composition) 关系是关联关系的一种,是比聚合关系强的关系。它要求普通的聚合关系中代表整体的
对象负责代表部分对象的生命周期,组合关系是不能共享的。代表整体的对象需要负责保持部分对象和存活,
在一些情况下将负责代表部分的对象湮灭掉。代表整体的对象可以将代表部分的对象传递给另一个对象,由
后者负责	此对象的生命周期。换言之,代表部分的对象在每一个时刻只能与一个对象发生组合关系,由
后
者排他地负责生命周期。部分和整体的生命周期一样。 
以上关系的耦合度依次增强(关于耦合度的概念将在以后具体讨论,这里可以暂时理解为当一个类发生变更时,
对其造成的影响程度,影响越小则耦合度越弱,影响越大耦合度越强)。由定义我们已经知道,依赖关系实
际上是一种比较弱的关联,聚合是一种比较强的关联,而组合则是一种更强的关联,所以笼统的来区分的话,
实际上这四种关系、都是关联关系。

依赖注入概念

1.英文名Dependency Injection 
2.IOC的作用:
	降低程序间的耦合(依赖关系)
3.依赖关系的管理
	以后都交给spring来维护
在当前类需要用到其它类的对象,由spring为我们提供,我们只需要在配置文件中说明依赖关系的维护,这就称之为依赖注入。

分类

能注入的的数据:基本类型和String,其他bean类型,复杂类型/集合类型

注入的方式

构造函数提供
1.使用的标签:constructor-arg
2.标签出现的位置:bean标签的内部
3.标签中的属性:
	type:用于指定要注入的数据的数据类型,该数据类型也是构造函数中某个或某些参数类型
	index:用于指定要注入的数据给定构造函数中指定索引位置的参数赋值。索引的位置从零开始
	name:用于指定给构造函数中指定名称的参数赋值
	==================================================================
	value=用于停工基本数据类型和String类型的数据
	ref:用于提供指定其他bean类型的数据。他指的就是在spring的Ioc核心容器中出现过的bean对象
优势:在获取bean对象是,注入数据是必须操作,确保了bean对象有参数
弊端:改变了bean对象实例化方式,在创建对象是必须写这些数据
<bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl" >
    <constructor-arg name="name" value="yaosai"></constructor-arg>
    <constructor-arg name="age" value="121"></constructor-arg>
    <constructor-arg name="birthday" ref="now"></constructor-arg>
</bean>
set方法注入
1.使用的标签:property
2.标签出现的位置:bean标签中
3.属性:
	name:
	value:
	ref:
通过调用对象的set方法对其进行依赖注入
优势:创建对象时,对参数的类型和个数没有限制
弊端:不能保证某个属性必须被注入
<bean id="accountService02" class="com.itheima.service.impl.AccountServiceImpl02" >
    <property name="age" value="12"></property>
    <property name="name" value="yao"></property>
    <property name="birthday" ref="now"></property>
</bean>
使用注解提供
复杂类型注入
1.用于注入集合类型的对象
2.用于给list结构集合注入的标签
	list,array,set
	 <property name="array">
        <array>
            <value>AAA</value>
            <value>BBB</value>
            <value>CCC</value>
        </array>
    </property>
3.用于给map结构集合注入的标签
	map prop(value只能写在标签中,value属性)
	<property name="map">
        <map>
            <entry key="first" value="AAA"></entry>
            <entry key="second" value="BBB"></entry>
            <entry key="third" value="CCC"></entry>
        </map>
    </property>
    <property name="properties">
        <props>
            <prop key="first" >AAA</prop>
            <prop key="second" >AAA</prop>
            <prop key="third" >AAA</prop>
        </props>
    </property>

Spring中注解

在bean配置文件的配置

在beans标签下
	<context:component-scan base-package="com.itheima"></context:component-scan>

注解的分类

1.用于创建对象的  //相当于bean标签
	@Component   
		位置:类上
		作用:把当前类对象存入sping容器中
		属性:value:用于指定bean的id。当我们不写时,默认为当前类名,且首字母小写
	@Controller //一般用于表现层
	@Service  //一般用于业务层
	@Repository  //一般用于持久层
	以上三个的作用和Component的作用相同
	他们三个时spring框架为我们提供明确的三层使用的注解,是我们对三层对象更加清晰
2.用于依赖注入的  //相当于properties标签
	注解依赖注入不能注入复杂数据类型的对象
	@Autowired
		位置:一般是属性上...
		作用:给当前属性赋值,spring会先从容器中找符合当前属性类型的对象
			如果只有一个,直接赋值
			如果有多个,他会根据当前属性的变量名与容器中对性的id进行匹配,如果有一样的就直接通
			过容器赋值,如果没有一样的就报错
		细节:在注解注入时,set方法不是必须的,也不用写对应的构造方法
	@Qualifier
		位置:成员变量,方法等
		作用:在按照类中注入的基础上再按照名称注入。他在给类成员注入时必须和@Aotowired一块用,但在给方法参数注入时不用
		属性:value:用于指定要注入bean的id
	@Resource
		位置:成员变量,方法等
		作用: 直接按照bean的id注入。他可以独立使用
		属性:value:关于指定要注入bean的id 
	以上三个注解都只能注入bean对象而不能注入int和String对象
	@Value
		作用:用于注入基本类型和String类型的数据
		属性:
			value:用于指定数据的值。它可以使用spring中的SpEL(也就是spring的el表达式)
				SpEl的写法:${表达式}
3.用于改变作用范围的 //相当于bean标签中的scope属性
	@Scope
		位置:类,方法
		作用:用于指定bean的作用范围
		属性:
			value:指定范围的取值。常用取值:singleton,prototype
4.和生命周期相关的  //相当于bean标签的init-method和destroy-method属性
		@PreDestroy
			作用:用于指定销毁方法
		@PreConstruct
			作用:用于指定初始化方法

新注解(彻底清除bean.xml里的标签)

*.需要有一个类来代替原来的xml文件,解决单靠注解解决不了的问题,例如
	1.xml文件中必须指定spring容器创建时扫描的包
	2.xml文件需要写一些不是我们写的类的bean,注解不能把这些bean存到核心容器中
1.Configuration
	位置:类上
	作用:指定当前类是个配置类
	细节:当配置类作为AnnotationConfigApplicationContext对象创建的参数时,该注解可以不写
2.ComponentScan()
	位置:类上
	作用:指定spring在创建容器要扫描的包
	属性:value(basePackages)指定spring容器创建时扫描的包
3.Bean
	位置:方法上
	作用:把该方法的返回值作为bean存到核心容器中
	属性:
		name:用于指定返回值的id(默认值为当前方法名)
	细节:
		当我们使用注解配置方法时,如果方法有参数,spring框架会去容器中查找有没有可用的bean对象。查找方式和Autowired注解作用一样
		用Scope标签还可以设置该对象是单例的还是多例的		
4.Import
	位置:类上
	作用:用于导入其他的配置类(这个类可以没有Configuration注解)
	属性为:
		value:用于指定其他配置类的字节码 
					当我们使用Import的注解后,有Import注解的类就是父类,二导入的都是子配置类
5.PropertySource()
	位置:类上
	作用:用于指定properties文件的位置
	属性:
		value:指定文件的名称和路径
					关键字:classpath

说点自己想说的

我们写几个工程就会发现,注解开发和配置文件开发都不是那么简单,都有繁琐的步骤
我觉得在开发中,第一要根据公司要求来用。
第二,在导入jar中的类时,我们不能直接在类上写注解,这个时候,用配置文件的方式就更加简单。导入我们写的类时,显而易见,用注解的方式更加简单。
总而言之,在开发中合理利用各种框架,让我们写的代码更少,更简单

spring整合junit问题

1.应用程序的入口是main方法
2.junit没有main方法也能执行,
其实是junit继承了一个main方法,
该方法就会判断当前测试类中哪些方法有@Test注解,junit就会让有@Test注解的方法执行
3.junit不知道我们是否用了spring框架,所以它在创建对象时使用new的方法创建的。
4.由以上三点可知,当测试方法执行时,没有ioc容器,junit不能识别其中的spring注解,无法实现功能

AOP

代理模式

动态代理

	特点:字节码随用随创建,随用随加载
	作用:不修改源码的基础上对方法增强
	分类:
		基于接口的动态代理
		基于子类的动态代理

基于接口的动态代理

		涉及的类Proxy
		提供者:JDK官方
	如何创建代理对象:
		使用Proxy类中的newProxyInstance方法
	创建代理对象的要求:
		被代理对象至少要实现一个接口
	newProxyInstance方法的参数
		ClassLoader:类加载器(被代理对象)
			它是用于加载代理就像的字节码的,和被代理就像使用相同的类加载器
		Class[]:字节码数组 (接口的字节码数组)
			它是用于让代理对象和被代理对象实现相同的类,即拥有相同的方法的
		InvocationHandler:用于提供增强的代码
			他是让我们写入和代理,我们一般都是写一个该接口的实现类,通常情况下都是匿名的内部类,但不是必须的。
			此接口的实现类都是谁用谁写
public class Client {
    static Producer producer = new Producer();
    public static void main(String[] args) {
        IProducer proxyProducer =(IProducer) Proxy.newProxyInstance(IProducer.class.getClassLoader(), producer.getClass().getInterfaces(), new InvocationHandler() {
              /**
             * 调用任何方法都会调用该方法
             * 修改所有被代理对象的方法,也可以不修改
             * @param proxy //代理对象
             * @param method //调用者调用的方法
             * @param args //调用者传过来的对象
             * @return
             * @throws Throwable
             */

            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println(proxy instanceof IProducer);
                float money=(Float)args[0];
                if (method.getName()=="saleProduct"){
                    System.out.println("赠送鼠标垫和无线鼠标");
                    money=money*(float) 0.8;
                    return method.invoke(producer, money);
                }else if(method.getName()=="afterService"){
                    money=money*(float)0.7;
                    return method.invoke(producer, money);
                }else{
                    return method.invoke(producer, args);
                }
            }
        });
        proxyProducer.saleProduct((float) 200.0);
        proxyProducer.afterService((float)200.0);
    }
}

基于子类的动态代理

*要求有第三方jar包的支持
	maven的dependency
		<dependency>
	     <groupId>cglib</groupId>
	        <artifactId>cglib</artifactId>
	        <version>2.1_3</version>
	    </dependency>
	涉及的类:Enhancer
		提供者:第三方cglib官方
	如何创建代理对象:
		使用Enhancer类中的create方法
	创建代理对象的要求:
		被代理类不能是最终类
	create方法的参数
		Class:字节码
			它是用于加载代理就像的字节码的,和被代理就像使用相同的类加载器
		Callback:用于提供增强的代码
			他是让我们写入和代理,我们一般都是写一个该接口的实现类,通常情况下都是匿名的内部类,但不是必须的。
			此接口的实现类都是谁用谁写
			一般我们写的都是该接口的子接口的实现类:MenthodInterceptor
	final Producer producer =new Producer();
    Producer proxyInstance = (Producer) Enhancer.create(producer.getClass(), new MethodInterceptor() {
        public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
            if (method.getName().equals("saleProduct")) {
                float money = (float) ((Float)objects[0]*0.8);
                return method.invoke(producer, money);
            }
            return method.invoke(producer, objects);
        }
    });
    proxyInstance.saleProduct((float) 12.0);

AOP概念

什么是aop

	AOP的全称是Aspect-Oriented Programming,以为面向切面编程,通过预编译方式和运行期动态代理实现程序功能的维护的一种技术。
	AOP是OOP的一种延续,是软件开发的热点。

AOP的作用及优势

	作用:
		在程序运行期间,不修改源码对已有方法进行增强。
	优势:
		减少重复代码
		提高开发效率
		增强代码可维护性

AOP实现方式

	使用动态代理技术

Spring中的AOP

相关术语

	1.连接点-Joinpoint
		要代理对象所有方法
		官方:所谓连接点是指那些被拦截到的点。在spring中,这些点指的是方法,因为spring只支持方法类型的连接点
	2.切入点-Pointcut
		要代理对象中要增强的方法
		官方:所谓切入点是指我们要对那些Joinpoint进行拦截的定义。
	3.通知(增强)-Advice
		对要增强的方法增强的代码
		类型:前置通知(原代码前的增强),后置通知(原代码后的增强),异常通知(增强代码或原代码出异常后的代码,即catch里的代码)
		最终通知(最后的执行的代码,即finally里的代码),环绕通知(指整个增强代码)
	4.引介-Introduction
	5.目标对象-Target
		代理的目标对象
	6.织入-Weaving
		是指把增强应用到目标对象来创建新的代理对象的过程。
		spring采用动态代理植入,而AspectJ采用编译器织入和类装载器织入。
	7.代理-Proxy
		代理对象
	8.切面-Aspect
		是指切入点和通知的结合。

通知的类型图解

基于xml的AOP配置

1.把被代理对象和增强方法对象加到spring容器中
2.使用aop:config标签表名开始AOP的配置
3.使用aop:aspect标签表明配置切面
	id属性:是指定该切面的id
	ref属性:是指定通知类bean的id
4.在aop:before标签内部使用对应标签来配置通知的类型
	我们现在是类是让printLog方法在切入点方法执行之前执行,所以是前置通知
	aop:before:表示配置前置通知
		method属性:用于指定Logger类中那个方法是前置通知
		pointcut属性:用于指定切入点表达式,该表达式的含义指的是对业务层中哪些方法增强
5.切入点表达式的写法:
	关键字:execution(表达式)
	表达式:
		访问修饰符 返回值 包名.包名.包名...类名.方法名(参数列表)
	标准的表达式写法:
		public void com.itheima.service.impl.AccountServiceImpl.saveAccount()
	访问修饰符可以省略
		void com.itheima.service.impl.AccountServiceImpl.saveAccount()
	返回值可以使用通配符代替,表示任意返回值
		* com.itheima.service.impl.AccountServiceImpl.saveAccount()
	包名可以使用通配符,表示任意包。但又集集堡就需要写几个 *. 
		* *.*.*.*.AccountServiceImpl.saveAccount()
	包名可以使用".."表示当前包及其子包
		* *..AccountServiceImpl.saveAccount()
	类名和方法名都可以使用*来实现通配
		* *..*.*()
	参数列表:
			可以直接写数据类型
				基本类型直接写名称 int
				引用数据类型写包.名类名的方式 java.lang.String
			可以使用通配符表示任意类型,但是必须有参数
			可以使用..表示有无参数均可,有参数可以是任意类型
	全通配写法
			* *..*.*(..)
	一般这样写
			* com.itheima.service.impl.*.*(..)//表示业务层中的所用方法
6.配置切入点表达式
	标签名:aop:pointcut
	属性:
		id:切入点的唯一标识
		expression:用于指定表达式的内容
	位置:
		它可以写在aop:aspect标签内,只能在某个切面内使用
		也可以写在aop:aspect标签外,aop:config标签内,能在此配置下所有切面中使用,
		但是由于xml约束的原因,如果要写到切面外,那么只能写到所有用切面之前。
7.配置不同通知
	前置通知:aop:before
		<aop:before method="beforePrintLog" pointcut="execution(* *.*.*.*.*.saveAccount(..))"></aop:before>
	后置通知:aop:after-returning
		<aop:after-returning method="afterReturningPrintLog" pointcut="execution(* *.*.*.*.*.saveAccount(..))"></aop:after-returning>
	异常通知:aop:after-throwing
		<aop:after-throwing method="afterThrowingPrintLog" pointcut="execution(* *.*.*.*.*.saveAccount(..))"></aop:after-throwing>
	最终通知:aop:after
		<aop:after method="afterPrintLog" pointcut="execution(* *.*.*.*.*.saveAccount(..))"></aop:after>
8.环绕通知:aop:around
	配置:<aop:around method="aroundPrintLog" pointcut-ref="servicePointcut"></aop:around>
	特点:
		环绕通知与其他通知不同,其他通知只需要写一个通知的代码即可,
		而环绕通知是模拟了proxy代理对象的过程,程序员需要在通知方法模拟代理模式的代理过程,一个通知可以代替其他所有通知,
		这样增加了通知的耦合程度,减少了代码量,当各个通知有固定的格式时用一个环绕通知代替更加方便。
	写法:
		Spring框架为我们提供了一个接口,ProceedingJoinPoint。该接口有一个方法proceed(),
		此方法就相当于明确调用切入点方法,即Proxy中的newProxyInstance方法,该接口可以作为环绕通知的方法参数,
		在程序执行时,spring框架会为我们提供该接口的实现类供我们使用
		public Object aroundPrintLog(ProceedingJoinPoint pjp){
	        Object rtValue=null;
	        try {
	            System.out.println("前置通知");
	            Object[] args = pjp.getArgs();
	            rtValue= pjp.proceed(args);
	            System.out.println("后置通知");
	        } catch (Throwable throwable) {
	            System.out.println("异常通知");
	            throwable.printStackTrace();
	        }finally {
	            System.out.println("最终通知");
	        }
	        return rtValue;
	    }

基于annotation的AOP配置

1.首先要设置spring容器在创建时要扫描的包
	<context:component-scan base-package="com.itheima"></context:component-scan>
2.其次要用注解把需要切入的类和通知类放到spring容器中
3.在通知类中写需要写的注解
	1.让spring容器知道你是一个通知类
		@Aspect注解写到Aspect类上
	2.配置切入点表达式
		@Pointcut("execution("表达式")
	    public void pointcut(){}
	3.在通知方法上添加各个通知的注解,以及他们的切入点
		@Before("pointcut()")
		@Before("pointcut()")
		@AfterThrowing("pointcut()")
		@After("pointcut()")
		@Around("pointcut()")

Spring中JdbcTemplate

<dependency>
  <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.0.2.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>5.0.2.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-tx</artifactId>
    <version>5.0.2.RELEASE</version>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.6</version>
</dependency>

Spring基于xml的事务控制

<!-- spring中基于XML的声明式事务控制配置步骤
    1、配置事务管理器
    2、配置事务的通知
            此时我们需要导入事务的约束 tx名称空间和约束,同时也需要aop的
            使用tx:advice标签配置事务通知
                属性:
                    id:给事务通知起一个唯一标识
                    transaction-manager:给事务通知提供一个事务管理器引用
    3、配置AOP中的通用切入点表达式
    4、建立事务通知和切入点表达式的对应关系
    5、配置事务的属性
           是在事务的通知tx:advice标签的内部

 -->
<!-- 配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"></property>
</bean>

<!-- 配置事务的通知-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
    <!-- 配置事务的属性
            isolation:用于指定事务的隔离级别。默认值是DEFAULT,表示使用数据库的默认隔离级别。
            propagation:用于指定事务的传播行为。默认值是REQUIRED,表示一定会有事务,增删改的选择。查询方法可以选择SUPPORTS。
            read-only:用于指定事务是否只读。只有查询方法才能设置为true。默认值是false,表示读写。
            timeout:用于指定事务的超时时间,默认值是-1,表示永不超时。如果指定了数值,以秒为单位。
            rollback-for:用于指定一个异常,当产生该异常时,事务回滚,产生其他异常时,事务不回滚。没有默认值。表示任何异常都回滚。
            no-rollback-for:用于指定一个异常,当产生该异常时,事务不回滚,产生其他异常时事务回滚。没有默认值。表示任何异常都回滚。
    -->
    <tx:attributes>
        <tx:method name="*" propagation="REQUIRED" read-only="false"/>
        <tx:method name="find*" propagation="SUPPORTS" read-only="true"></tx:method>
    </tx:attributes>
</tx:advice>

<!-- 配置aop-->
<aop:config>
    <!-- 配置切入点表达式-->
    <aop:pointcut id="pt1" expression="execution(* com.itheima.service.impl.*.*(..))"></aop:pointcut>
    <!--建立切入点表达式和事务通知的对应关系 -->
    <aop:advisor advice-ref="txAdvice" pointcut-ref="pt1"></aop:advisor>
</aop:config>

Spring基于注解的事务控制

 <!-- spring中基于注解 的声明式事务控制配置步骤
        1、配置事务管理器
        2、开启spring对注解事务的支持
        3、在需要事务支持的地方使用@Transactional注解-->
        <!-- 配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 开启spring对注解事务的支持-->
<tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
在需要事务支持的地方使用@Transaction注解
@Transactional(propagation = Propagation.S  UPPORTS,readOnly = true)

笔记借鉴黑马教程
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

狴犴ys

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值