spring(IOC,DI,AOP)详解

第一章-Spring概述

Spring介绍
概述:Spring 是一个开源框架,是为了解决企业应用程序开发复杂性而创建的。
框架的主要优势之一就是其分层架构,分层架构允许您选择使用哪一个组件,同时为 J2EE 应用程序开发提供集成的框架。
简单来说,Spring是一个分层的JavaSE/EE full-stack(一站式) 轻量级开源框架。
一站式:Spring提供了三层解决方案.

Spring 的发展历程
1997 年 IBM 提出了 EJB 的思想
1998 年, SUN 制定开发标准规范 EJB1.0
1999 年, EJB1.1 发布
2001 年, EJB2.0 发布
2003 年, EJB2.1 发布
2006 年, EJB3.0 发布
Rod Johnson(spring 之父)
Expert One-to-One J2EE Design and Development(2002),阐述了 J2EE 使用 EJB 开发设计的优点及解决方案
Expert One-to-One J2EE Development without EJB(2004),阐述了 J2EE 开发不使用 EJB 的解决方式(Spring 雏形)
2017 年 9 月份发布了 spring 的最新版本 spring 5.0 通用版(GA)

Spring的优点
1.方便解耦,简化开发
通过Spring提供的IoC容器,我们可以将对象之间的依赖关系交由Spring进行控制,避免硬编码所造成的过度程序耦合。有了Spring,用户不必再为单实例模式类、属性文件解析等这些很底层的需求编写代码,可以更专注于上层的应用。
2.AOP编程的支持
通过Spring提供的AOP功能,方便进行面向切面的编程,许多不容易用传统OOP实现的功能可以通过AOP轻松应付。
3.声明式事务的支持
在Spring中,我们可以从单调烦闷的事务管理代码中解脱出来,通过声明式方式灵活地进行事务的管理,提高开发效率和质量。
4.方便程序的测试
可以用非容器依赖的编程方式进行几乎所有的测试工作,在Spring里,测试不再是昂贵的操作,而是随手可做的事情。例如:Spring对Junit4支持,可以通过注解方便的测试Spring程序。
5.方便集成各种优秀框架
Spring不排斥各种优秀的开源框架,相反,Spring可以降低各种框架的使用难度,Spring提供了对各种优秀框架(如Struts,Hibernate、Hessian、Quartz)等的直接支持。
6.降低Java EE API的使用难度
Spring对很多难用的Java EE API(如JDBC,JavaMail,远程调用等)提供了一个薄薄的封装层,通过Spring的简易封装,这些Java EE API的使用难度大为降低。

Spring的体系结构
在这里插入图片描述

第二章-IOC

程序的耦合
耦合性(Coupling),也叫耦合度,是对模块间关联程度的度量。耦合的强弱取决于模块间接口的复杂性、调用模块的方式以及通过界面传送数据的多少。模块间的耦合度是指模块之间的依赖关系,包括控制关系、调用关系、数据传递关系。模块间联系越多,其耦合性越强,同时表明其独立性越差( 降低耦合性,可以提高其独立性)。 耦合性存在于各个领域,而非软件设计中独有的,但是我们只讨论软件工程中的耦合。

自定义IOC(工厂模式解耦)

  1. 原始方式
    • 方式: 创建类, 直接根据类new对象
    • 优点: 好写, 简单
    • 缺点: 耦合度太高, 不好维护
  2. 接口方式
    • 方式: 定义接口, 创建实现类. 接口=子类的对象
    • 优点: 耦合度相对原始方式 减低了一点
    • 缺点: 多写了接口, 还是需要改源码 不好维护
  3. 自定义IOC
    • 方式: 使用对象的话, 不直接new()了,直接从工厂里面取; 不需要改变源码
    • 思路:
      在实际开发中我们可以把三层的对象都使用配置文件配置起来,当启动服务器应用加载的时候, 让一个类中的方法通过读取配置文件,把这些对象创建出来并存起来。在接下来的使用的时候,直接拿过来用就好了。那么,这个读取配置文件, 创建和获取三层对象的类就是工厂
      添加坐标依赖:
<dependencies>
    <!-- 解析 xml 的 dom4j -->
    <dependency>
      <groupId>dom4j</groupId>
      <artifactId>dom4j</artifactId>
      <version>1.6.1</version>
    </dependency>
    <!-- dom4j 的依赖包 jaxen -->
    <dependency>
      <groupId>jaxen</groupId>
      <artifactId>jaxen</artifactId>
      <version>1.1.6</version>
    </dependency>
    <!--单元测试-->
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.10</version>
      <scope>test</scope>
    </dependency>
  </dependencies>

IOC概述
IOC(inversion of control)的中文解释是“控制反转”,对象的使用者不是创建者. 作用是将对象的创建 反转给spring框架来创建和管理。
控制反转怎么去理解呢。 其实它反转的是什么呢,是对象的创建工作。 举个例子:平常我们在servlet或者service里面创建对象,都是使用new 的方式来直接创建对象,现在有了spring之后,我们就再也不new对象了,而是把对象创建的工作交给spring容器去维护。我们只需要问spring容器要对象即可
ioc 的作用:削减计算机程序的耦合(解除我们代码中的依赖关系)。
配置文件详解(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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--
        bean标签: 注册bean, 把对象交给Spring管理
        1.【掌握】属性:
            id/name属性: 随便写,作为bean的唯一标识,不要重复(建议写接口的名字,首字母小写)
            class属性:  类的全限定名
            scope属性:  singleton 单例,  不管获得多少次 都是同一个, 创建出来存到Spring容器里面  【默认】
                        prototype 多例,  每获得一次 就创建一个新的对象,创建出来不会存到Spring容器里面

                        request 把创建的对象存到request域,针对web项目【了解】
                        session 把创建的对象存到session域,针对web项目【了解】
                        我们一般也是单例的, 特殊情况才是设置为prototype多例 eg:struts2里面的action
       2. 【了解】的属性
            init-method属性: 指定初始化方法,写方法名
            destroy-method属性: 指定销毁的方法, 象征着当前对象从Spring容器里面移除了 写方法名
    -->
    <bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl" scope="prototype"
        init-method="initMethod" destroy-method="destoryMethod"
    ></bean>

</beans>
  • id/name属性
    用于标识bean , 其实id 和 name都必须具备唯一标识 ,两种用哪一种都可以。但是一定要唯一、 一般开发中使用id来声明.
  • class属性: 用来配置要实现化类的全限定名
  • scope属性: 用来描述bean的作用范围
    singleton: 默认值,单例模式。spring创建bean对象时会以单例方式创建。(默认), 使用的都是同一个对象(同一个id获得的). 单例的bean存到Spring容器里面
    prototype: 多例模式。spring创建bean对象时会以多例模式创建。 使用的不是同一个对象(同一个id获得的), 使用一个 创建一个. 多例的bean不会存到Spring容器里面
    request: 针对Web应用。spring创建对象时,会将此对象存储到request作用域。
    session: 针对Web应用。spring创建对象时,会将此对象存储到session作用域。
  • init-method属性:spring为bean初始化提供的回调方法
  • destroy-method属性:spring为bean销毁时提供的回调方法. 销毁方法针对的都是单例bean , 如果想销毁bean , 可以关闭工厂
    bean的作用范围和生命周期
  • 单例对象: scope=“singleton”
    一个应用只有一个对象的实例。它的作用范围就是整个引用。
    生命周期:
    对象出生:当应用加载,创建容器时,对象就被创建了。
    对象活着:只要容器在,对象一直活着。
    对象死亡:当应用卸载,销毁容器时,对象就被销毁了。
  • 多例对象: scope=“prototype”
    每次访问对象时,都会重新创建对象实例。
    生命周期:
    对象出生:当使用对象时,创建新的对象实例。
    对象活着:只要对象在使用中,就一直活着。
    对象死亡:当对象长时间不用时,被 java 的垃圾回收器回收了.
    spring 中工厂的类结构图
  • ClassPathXmlApplicationContext:它是从类的根路径下加载配置文件
  • FileSystemXmlApplicationContext:它是从磁盘路径上加载配置文件,配置文件可以在磁盘的任意位置。
  • AnnotationConfigApplicationContext:当我们使用注解配置容器对象时,需要使用此类来创建 spring 容器。它用来读取注解。
    BeanFactory 和 ApplicationContext 的区别
    新旧工厂
  • 新工厂: 在工厂初始化的话的时候, 就会创建配置的所有的单例bean,存到Spring容器里面
  • 旧工厂(已经废弃了): 等用到对象的时候, 再创建
  • ApplicationContext 是现在使用的工厂
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
  • XmlBeanFactory是老版本使用的工厂,目前已经被废弃【了解】
BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));

两者的区别:
ApplicationContext加载方式是框架启动时就开始创建所有单例的bean,存到了容器里面
BeanFactory加载方式是用到bean时再加载(目前已经被废弃)
实例化Bean的三种方式【了解】
方式一:无参构造方法方式
需要实例化的类,提供无参构造方法
配置代码

<bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl"></bean>

方式二:静态工厂方式
需要额外提供工厂类 , 工厂方法是静态方法

public class StaticFactory {
	public static Object getBean(){
		return new AccountServiceImpl02();
	}
}

配置代码

<!--方式二:静态工厂方式  -->	
<bean  id="accountService02" class="com.itheima.utils.StaticFactory" factory-method="getBean"/>

方式三:实例工厂实例化的方法
创建实例化工厂类

public class InstanceFactory {
	public Object getBean(){
		return new AccountServiceImpl03();
	}
}

配置

<!-- 方式三: 实例化工厂 -->
<!--注册工厂  -->
<bean id="factory" class="com.itheima.utils.InstanceFactory"></bean>
<!--引用工厂  -->
<bean  id="accountService03" factory-bean="factory" factory-method="getBean"/>

一般情况下不会使用第二和三种, 主要使用第一种

第三章-依赖注入(DI)

依赖注入全称是 dependency Injection 翻译过来是依赖注入.其实就是如果我们托管的某一个类中存在属性,需要spring在创建该类实例的时候,顺便给这个对象里面的属性进行赋值。 这就是依赖注入。
现在, Bean的创建交给Spring了, 需要在xml里面进行注册
我们交给Spring创建的Bean里面可能有一些属性(字段), Spring帮我创建的同时也把Bean的一些属性(字段)给赋值, 这个赋值就是注入.

  1. 注册: 把bean的创建交给Spring

  2. 依赖注入: bean创建的同时, bean里面可能有一些字段需要赋值, 这个赋值交给Spring, 这个过程就是依赖注入

  3. 构造方法方式注入

  4. set方法方式的注入

  5. P名称空间注入

  6. SpEL的属性注入

构造方法方式注入【掌握】

  • Java代码
public class AccountServiceImpl implements AccountService {
    private String name;
    public AccountServiceImpl(String name) {
        this.name = name;
    }
    @Override
    public void save() {
        System.out.println("AccountServiceImpl... save()"+name);

    }
}
  • 配置文件
<!--注册AccountService-->
 <bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl">
    <constructor-arg name="name" value="张三"></constructor-arg>
</bean>

set方法方式的注入【重点】
注入简单类型

  • java代码
public class AccountServiceImpl implements AccountService {
    private String name;

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public void save() {
        System.out.println("AccountServiceImpl... save()"+name);

    }
}
  • 配置文件
<bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl">
       <property name="name" value="李四"></property>
</bean>

注入数组类型

  • java代码
public class AccountServiceImpl implements AccountService {
    private String[] hobbys;

    public void setHobbys(String[] hobbys) {
        this.hobbys = hobbys;
    }

    @Override
    public void save() {
        System.out.println("AccountServiceImpl... save()"+ Arrays.toString(hobbys));

    }
}
  • 配置文件
<bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl">
        <property name="hobbys">
            <array>
                <value>篮球</value>
                <value>足球</value>
                <value>乒乓球</value>
                <value>排球</value>
            </array>
        </property>
    </bean>

注入Map类型

  • Java代码
public class AccountServiceImpl implements AccountService {
    private Map<String,String> map;

    public void setMap(Map<String, String> map) {
        this.map = map;
    }

    @Override
    public void save() {
        Set<Map.Entry<String, String>> set = map.entrySet();
        for (Map.Entry<String, String> entry : set) {
            System.out.println(entry.getKey()+":"+entry.getValue());
        }
        System.out.println("AccountServiceImpl... save()");

    }
}
  • 配置文件
<bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl">
     <property name="map">
         <map>
              <entry key="akey" value="aaa"/>
              <entry key="bkey" value="bbb"/>
              <entry key="ckey" value="ccc"/>
         </map>
     </property>
</bean>
或者

<bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl">
    <property name="map">
		<props>
			<prop key="akey">aaa</prop>
			<prop key="bkey">bbb</prop>
			<prop key="ckey">ccc</prop>
		</props>
	</property>
</bean>

注入Java对象类型

  • Java代码
   public class AccountServiceImpl implements AccountService {
          private AccountDao accountDao;
      
          public void setAccountDao(AccountDao accountDao) {
              this.accountDao = accountDao;
          }
          @Override
          public void save() {
      
              System.out.println("AccountServiceImpl... save()");
              accountDao.save();
      
          }
      }
  • 配置文件
<!--注册AccountService-->
<bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl">
    <property name="accountDao" ref="accountDao"></property>
</bean>
<!--注册accountDao-->
<bean id="accountDao" class="com.itheima.dao.impl.AccountDaoImpl">
</bean>

名称空间注入【了解】
p名称空间的方式

  • 提供属性的set方法
  • 在applicationContext.xml引入p命名空间xmlns:p=“http://www.springframework.org/schema/p”
<?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" xmlns:p="http://www.springframework.org/schema/p"
       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">
</beans>
  • 使用
<bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl" p:name="张三">
  	
</bean>

Spring3.0之后 SpEL的属性注入【了解】
这种方式是使用spring 提供的一种表达式方式去赋值, 如果是给前面提过的几个类型注入赋值,那么使用spEL 表达式来注入赋值倒显得繁琐。但是这个spEL 方式赋值,最大的好处在于,它能像EL表达式一般,在里面进行运算、 逻辑判断,还可以调用其它Bean的属性和方法给当前属性赋值

  • 语法格式 : #{spEL}
  • 类中存在一个属性 name , 并且给定 set方法。
  <property name="name" value="#{'张三'}" ></property>

小结

  1. 构造方法方式
    • 定义变量 ,提供构造方法
    • 在bean标签里面配置子标签constructor-arg
   <bean id="" class="">
   	<constructor-arg name="" value=""></constructor-arg>
   	<constructor-arg name="" ref=""></constructor-arg>
   </bean>
  1. Set方法方式
    • 2.1 步骤
      • 定义变量 ,提供Set方法
      • bean标签里面配置子标签property
    • 2.2 简单类型(基本类型, String)
   <bean id="" class="">
   	<property name="" value=""></property>
   </bean>
  • 2.3 数组类型
   <bean id="" class="">
   	<property name="">
   		<array>
   			<value></value>
   		</array>
   	</property>
   </bean>
  • 2.3 Map类型
   <bean id="" class="">
   	<property name="">
   		<map>
   			<entry key="" value=""></entry>
   		</map>
   	</property>
   </bean>
  • 2.4 对象类型
   <bean id="" class="">
   	<property name="" ref="">
   	</property>
   </bean>

使用Spring的IoC的实现账户的CRUD配置文件

<?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">
    <!--注册AccountService-->
    <bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl">
        <property name="accountDao" ref="accountDao"/>
    </bean>
    <!--注册accountDao-->
    <bean id="accountDao" class="com.itheima.dao.impl.AccountDaoImpl">
        <property name="queryRunner" ref="queryRunner"/>
    </bean>
    <!--注册queryRunner-->
    <bean id="queryRunner" class="org.apache.commons.dbutils.QueryRunner">
        <constructor-arg name="ds" ref="dataSource"/>
    </bean>
    <!--注册数据源-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="url" value="jdbc:mysql://localhost:3306/spring_day02?characterEncoding=utf8"/>
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="username" value="root"/>
        <property name="password" value="123456"/>
    </bean>
</beans>

测试案例

public class DbTest {
    @Test
    public void fun01() throws Exception {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        AccountService accountService = (AccountService) applicationContext.getBean("accountService");
        List<Account> list = accountService.findAll();
        System.out.println(list);
    }
}

@NonNull 注解和@Nullable 注解的使用
用 @Nullable 和 @NotNull 注解来显示表明可为空的参数和以及返回值。这样就够在编译的时候处理空值而不是在运行时抛出 NullPointerExceptions。

第四章-Spring的IOC注解开发

添加依赖

<dependencies>
    <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.0.2.RELEASE</version>
    </dependency>
 </dependencies>

引入context的命名空间
applicationContext.xml中需要引入context的命名空间,可在xsd-configuration.html中找到

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
</beans>

配置扫描
在bean标签内部,使用context:component-scan ,让spring扫描该基础包下的所有子包注解

<context:component-scan base-package="com.itheima"></context:component-scan>
  1. 在类上面添加@Component(“id”)
  2. 在applicationContext.xml 开启包扫描

用于创建对象的
相当于:
@Component
作用:
把资源让 spring 来管理。相当于在 xml 中配置一个 bean。
属性:
value:指定 bean 的 id。如果不指定id属性,默认 bean 的 id 是当前类的类名。首字母小写。

web里面的三层结构 中的所有类,在spring里面都称之为 Component (组件) , 但是它也提供了更详细的注解来针对不同的层级声明 。
三个衍生注解如下:
@Controller :修饰WEB层类 —>action | SpringMVC
@Service :修饰业务层类 —>service
@Repository :修饰DAO层类 —>dao

用于改变作用范围的@scope
@scope
singleton: 单例(默认)
prototype:多例
@Scope注解用来描述类的作用范围的,默认值singleton。如同xml中bean标签的属性scope .如果配置成多例的使用prototype。

@Scope("prototype")
@Component("accountService")
public class AccountServiceImpl implements AccountService {}

和生命周期相关的【了解】
初始化和销毁回调方法对应的注解
@PostConstrut:如同xml中bean标签的属性init-method ,用来设置spring框架初始化此类实例时调用的初始化方法,标注在此类的初始化方法上
@PreDestroy:如同xml中bean标签的属性init-method ,用来设置spring框架销毁此类实例时调用的销毁方法,标注在此类的销毁方法上
注意:这两个注解都是配在方法上的

总结:

  1. 注册Bean的 相当于配置了
    • @Component(“id”)
    • @Controller(“id”) 配置web层
    • @Service(“id”) 配置Service层
    • @Repository(“id”) 配置持久层 如果id不配, 默认就是类的名字,首字母小写
  2. 配置bean的作用范围
    • @Scope(“类型”)
      • singleton 单例【默认】
      • prototype 多例
  3. 配置和生命周期相关的
    • @PostConstruct init-method=""
    • @PreDestroy destroy-method=""

使用注解注入属性
@Value

  • 作用:
    注入基本数据类型和 String 类型数据的
  • 属性:
    value:用于指定值 , 可以通过表达式动态获得内容再赋值
  • 实例:
@Value("奥巴马")
private String name;

@Autowired

  • 作用:
    自动按照类型注入。当使用注解注入属性时, set 方法可以省略。它只能注入其他 bean 类型。
    如果只有一个实现类, 可以自动注入成功
    如果有两个或者两个以上的实现类, 找到变量名一致的id对象给注入进去, 如果找不到,就报错
  • 实例:
@Component("accountService")
public class AccountServiceImpl implements AccountService {
    @Autowired
    //当有多个AccountDao实现类时候, @Autowired会在在Spring容器里面找id为accountDao的对象注入,找不到就报错
    private AccountDao accountDao;
    @Override
    public void save() {
        System.out.println("AccountServiceImpl---save()");
        accountDao.save();
    }
}

@Qualifier

  • 作用
    在自动按照类型注入(@Autowired)的基础之上,再按照Bean的id注入。
    它在给字段注入时不能独立使用,必须和@Autowire一起使用;
    但是给方法参数注入时,可以独立使用。
  • 属性
    value:指定bean的id。
  • 实例
@Component("accountService")
public class AccountServiceImpl implements AccountService {
    @Autowired
    @Qualifier(value = "accountDao02")
    private AccountDao accountDao;
    @Override
    public void save() {
        System.out.println("AccountServiceImpl---save()");
        accountDao.save();
    }
}

@Resource
如果上面一个接口有多种实现,那么现在需要指定找具体的某一个实现,那么可以使用

@Component("accountService")
public class AccountServiceImpl implements AccountService {
    @Resource(name = "accountDao02")
    private AccountDao accountDao;
    @Override
    public void save() {
        System.out.println("AccountServiceImpl---save()");
        accountDao.save();
    }
}

小结:

  1. 注入简单类型 @Value(“值/表达式”)
  2. 注入对象类型
    • 如果只有一个实现类, 建议使用@Autowired
    • 如果有多个实现类, 建议使用@Resource("name=“id”)

混合开发
注解和XML比较
在这里插入图片描述

  • xml
    • 优点: 方便维护, 改xml文件
    • 缺点: 相对注解而言, 麻烦一点
  • 注解
    • 优点: 开发简洁方便
    • 缺点: 维护没有xml那么方便, 需要改源码

混合开发特点
使用xml(注册bean)来管理bean
使用注解来注入属性

混合开发环境搭建
创建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: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
     ">
</beans>

配置扫描

<context:component-scan base-package="com.itheima" />
  • 在xml配置中添加Bean的管理
  • 在被管理bean对应的类中,为依赖添加注解配置

小结:

  1. xml注册(管理bean)
  2. 注解注入(给对象里面字段/属性赋值)

纯注解测试实现
@Configuration

  • 作用:
    用于指定当前类是一个spring配置类,当创建容器时会从该类上加载注解。
    获取容器时需要使用AnnotationApplicationContext(类.class)。
  • 属性:
    value:用于指定配置类的字节码
  • 示例代码:
@Configuration
public class SpringConfiguration {

}

@ComponentScan

  • 作用:
    用于指定spring在初始化容器时要扫描的包。作用和在spring的xml配置文件中的: <context:component-scan base-package=“com.itheima”/>是一样的。
  • 属性:
    basePackages:用于指定要扫描的包。和该注解中的value属性作用一样。
  • 示例代码:
@Configuration
@ComponentScan("com.itheima")
public class SpringConfiguration {

}

@Bean

  • 作用:
    该注解只能写在方法上,表明使用此方法创建一个对象,并且放入spring容器。
  • 属性:
    name:给当前@Bean注解方法创建的对象指定一个名称(即bean的id)。
  • 示例代码:
/**
 * 该类是一个配置类,它的作用和bean.xml是一样的
 */
@Configuration
@ComponentScan("com.itheima")
public class SpringConfiguration {

    private String driver = "com.mysql.jdbc.Driver";
    private String url = "jdbc:mysql:///spring_day02";
    private String username = "root";
    private String password = "123456";
    /**
     * 用于创建一个QueryRunner对象
     * @param dataSource
     * @return
     */
    @Bean("runner")
    public QueryRunner createQueryRunner(@Qualifier(value ="dataSource") DataSource dataSource){
        return new QueryRunner(dataSource);
    }
    /**
     * 用于创建DataSource
     * @return
     * @throws PropertyVetoException
     */
    @Bean(name = "dataSource")
    public DataSource createDataSource() throws PropertyVetoException {
        ComboPooledDataSource ds = new ComboPooledDataSource();
        ds.setDriverClass(driver);
        ds.setJdbcUrl(url);
        ds.setUser(username);
        ds.setPassword(password);
        return ds;
    }

}

@Import

  • 作用:
    用于导入其他配置类,在引入其他配置类时,可以不用再写@Configuration注解。当然,写上也没问题。
  • 属性:
    value[]:用于指定其他配置类的字节码。
  • 示例代码:
/**
 * 该类是一个配置类,它的作用和bean.xml是一样的
 */
@Configuration
@ComponentScan("com.itheima")
@Import({JdbcConfig.class})
public class SpringConfiguration {


}
public class JdbcConfig {
    private String driver = "com.mysql.jdbc.Driver";
    private String url = "jdbc:mysql:///spring_day02";
    private String username = "root";
    private String password = "123456";
    /**
     * 用于创建一个QueryRunner对象
     * @param dataSource
     * @return
     */
    @Bean("runner")
    @Scope("prototype")
    public QueryRunner createQueryRunner(@Qualifier(value ="dataSource") DataSource dataSource){
        return new QueryRunner(dataSource);
    }
    /**
     * 用于创建DataSource
     * @return
     * @throws PropertyVetoException
     */
    @Bean(name = "dataSource")
    public DataSource createDataSource() throws PropertyVetoException {
        ComboPooledDataSource ds = new ComboPooledDataSource();
        ds.setDriverClass(driver);
        ds.setJdbcUrl(url);
        ds.setUser(username);
        ds.setPassword(password);
        return ds;
    }


}

@PropertySource

  • 作用:
    用于加载.properties文件中的配置。例如我们配置数据源时,可以把连接数据库的信息写到properties配置文件中,就可以使用此注解指定properties配置文件的位置。
  • 属性:
    value[]:用于指定properties文件位置。如果是在类路径下,需要写上classpath:
  • 示例代码:

jdbc.properties

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/spring_day02
jdbc.username=root
jdbc.password=123456

JdbcConfig.java
@PropertySource(value = {“classpath:jdbc.properties”})
public class JdbcConfig {
@Value(" j d b c . u r l " ) p r i v a t e S t r i n g u r l ; @ V a l u e ( " {jdbc.url}") private String url; @Value(" jdbc.url")privateStringurl;@Value("{jdbc.driver}")
private String driver;
@Value(" j d b c . u s e r n a m e " ) p r i v a t e S t r i n g u s e r n a m e ; @ V a l u e ( " {jdbc.username}") private String username; @Value(" jdbc.username")privateStringusername;@Value("{jdbc.password}")
private String password;
@Bean(“queryRunner”)
public QueryRunner createQueryRunner(DataSource dataSource){
QueryRunner queryRunner = new QueryRunner(dataSource);
return queryRunner;
}
@Bean(“dataSource”)
public DataSource createDataSource(){
DruidDataSource dataSource = new DruidDataSource();
dataSource.setUrl(url);
dataSource.setDriverClassName(driver);
dataSource.setUsername(username);
dataSource.setPassword(password);
return dataSource;
}
}
通过注解获取容器

ApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfiguration.class);

小结:
在这里插入图片描述

第五章-Spring整合测试

在测试类中,每个测试方法都有以下两行代码:
ApplicationContext ac = new ClassPathXmlApplicationContext(“bean.xml”);
AccountService as= ac.getBean(“accountService”,AccountService.class);
这两行代码的作用是获取容器,如果不写的话,直接会提示空指针异常。所以又不能轻易删掉。

导入spring整合Junit的坐标

<dependency>
  		<groupId>org.springframework</groupId>
  		<artifactId>spring-test</artifactId>
  		<version>5.0.2.RELEASE</version>
  	</dependency>

在测试类上面标记注解

@RunWith(SpringJUnit4ClassRunner.class)//指明运行的测试环境
//@ContextConfiguration("classpath:applicationContext.xml")//指明spring框架的加载的配置文件【有applicationContext.xml解使用这种】
@ContextConfiguration(classes = SpringConfiguration.class)//指明spring框架的加载的配置类【纯注解使用这种】
public class DbTest
{
    @Autowired
    private AccountService accountService;

    @Test
    public void testSaveAccount() throws Exception {
        Account account = new Account();
        account.setName("王二麻子");
        account.setMoney(100f);
        accountService.save(account);
    }

}

思考问题为什么不把测试类配到xml中

  • 在解释这个问题之前,先解除大家的疑虑,配到XML中能不能用呢?
    答案是肯定的,没问题,可以使用。
  • 那么为什么不采用配置到xml中的方式呢?
    这个原因是这样的:
    第一:当我们在xml中配置了一个bean,spring加载配置文件创建容器时,就会创建对象。
    第二:测试类只是我们在测试功能时使用,而在项目中它并不参与程序逻辑,也不会解决需求上的问题,所以创建完了,并没有使用。那么存在容器中就会造成资源的浪费。
    所以,基于以上两点,我们不应该把测试配置到xml文件中。

第六章-AOP相关的概念

什么是AOP
AOP:全称是AspectOriented Programming, 即面向切面编程。在不修改源码的基础上,对我们的已有方法进行增强。
说白了就是把我们程序重复的代码抽取出来,在需要执行的时候,使用动态代理的技术,进行增强
AOP实现原理
使用动态代理技术

  • JDK动态代理: 必须需要接口的
  • Cglib动态代理: 不需要接口的,只需要类就好了
    小结:
  1. AOP: 面向切面编程
  2. 作用: 不需要改变源代码 对目标方法进行增强
  3. 底层实现: 动态代理

在AOP 这种思想还没有出现的时候,我们解决 切面的问题思路无非有以下两种:

  1. 方式一:通过静态方法实现(缺点:需要修改源码,后期不好维护)
    把需要添加的代码抽取到一个地方,然后在需要添加那些方法中引用
  2. 方式二:通过继承方案来解决(缺点:需要修改源码,继承关系复杂,后期不好维护)
    抽取共性代码到父类, 子类在需要的位置,调用父类方法。
    上述两种方式的缺点
    都会打破原来代码的平静(也就是必须要修改代码 , 或者就是必须事先固定好。) 如果我们想在原有代码基础上扩展。 并且不改动原来的代码, 就可以使用AOP了。
    其实AOP 字面直译过来是面向切面编程,其实通俗一点它就是对我们的具体某个方法进行了增强而已。在之前我们对某个方法进行增强无非是两种手段 ,一种是装饰者模式 、 一种是代理模式 (静态代理 & 动态代理) 。 AOP 的底层使用的是动态代理方式 。

AOP 的底层动态代理实现有两种方案。
一种是使用JDK的动态代理。 这种是早前我们在前面的基础增强说过的。 这一种主要是针对有接口实现的情况。 它的底层是创建接口的实现代理类, 实现扩展功能。也就是我们要增强的这个类,实现了某个接口,那么我就可以使用这种方式了. 而另一种方式是使用了cglib 的动态代理,这种主要是针对没有接口的方式,那么它的底层是创建被目标类的子类,实现扩展功能.

小结:

  1. AOP的底层就是封装了动态代理
    • JDK的动态代理
    • CgLib的动态代理
  2. JDK的动态代理: 依赖接口的, 必须有接口
    CgLib的动态代理: 依赖类的(父类), 不需要接口的

学习spring中的AOP要明确的事

  • 开发阶段(我们做的)
    编写核心业务代码(开发主线):大部分程序员来做,要求熟悉业务需求。
    把公用代码抽取出来,制作成通知。(开发阶段最后再做):AOP编程人员来做。
    在配置文件中,声明切入点与通知间的关系,即切面:AOP编程人员来做。
  • 运行阶段(Spring框架完成的)
    Spring框架监控切入点方法的执行。一旦监控到切入点方法被运行,使用代理机制,动态创建目标对象的代理对象,根据通知类别,在代理对象的对应位置,将通知对应的功能织入,完成完整的代码逻辑运行。
    在spring中,框架会根据目标类是否实现了接口来决定采用哪种动态代理的方式。

AOP中的术语

  • JoinPoint: 连接点
    类里面哪些方法可以被增强,这些方法称为连接点. 在spring的AOP中,指的是所有现有的方法。
  • Pointcut: 切入点
    在类里面可以有很多方法被增强,但是实际开发中,我们只对具体的某几个方法而已,那么这些实际增强的方法就称之为切入点
  • Advice: 通知/增强
    增强的逻辑、称为增强,比如给某个切入点(方法) 扩展了校验权限的功能,那么这个校验权限即可称之为增强 或者是通知
    通知分为:
    前置通知: 在原来方法之前执行.
    后置通知: 在原来方法之后执行. 特点: 可以得到被增强方法的返回值
    环绕通知:在方法之前和方法之后执行. 特点:可以阻止目标方法执行
    异常通知: 目标方法出现异常执行. 如果方法没有异常,不会执行. 特点:可以获得异常的信息
    最终通知: 指的是无论是否有异常,总是被执行的。

Aspect: 切面
切入点和通知的结合
在这里插入图片描述
在这里插入图片描述

第七章-Spring中的AOP

前置通知
导入坐标

<dependencies>
    <!--Spring核心容器-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.0.2.RELEASE</version>
    </dependency>
    <!--SpringAOP相关的坐标-->
    <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjweaver</artifactId>
      <version>1.8.7</version>
    </dependency>
    
    <!--Spring整合单元测试-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-test</artifactId>
      <version>5.0.2.RELEASE</version>
    </dependency>
    <!--单元测试-->
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
      <scope>test</scope>
    </dependency>
  </dependencies>

定义被增强的业务逻辑类和切面类(增强的)

//被增强的类
public class AccountDaoImpl implements AccountDao {

    @Override
    public void save() {
        System.out.println("save()...");
    }
}

//增强的类(切面类)
public class MyAscept {
    public void checkPrivilege() {// 通知
        System.out.println("权限的校验...");
    }
}

xml中声明 增强的bean (扩展的bean) 和 被增强的bean (被扩展的bean)

<!--注册accountDao-->
<bean id="accountDao" class="com.itheima.dao.impl.AccountDaoImpl"/>
<!--注册增强(切面)-->
<bean id="myAscept" class="com.itheima.aspect.MyAscept"/>

定义aop的配置

 <!--配置切入点(哪个包下的哪个类哪个方法需要增强)
       expression="execution(* com.xyz.myapp.service.*.*(..))"
       第一个* 表示返回值 ,不管任何返回值。 匹配任意返回值
       com.xyz.myapp.service : 表示这个包下
       第二个* 表示这个包下的所有类
       第三个* 表示这个包下的所有类中的所有方法
       (..) : 这个表示方法的参数 .. 任意参数
       spring 根据这一套规则,能够找到具体哪一个方法来做增强了。
    -->
        -->
     <!--配置AOP-->
    <aop:config>
        <aop:pointcut id="pointCut01" expression="execution(* com.itheima.dao.impl.AccountDaoImpl.save(..))"/>
        <!--配置切面(切入点和通知的结合)-->
        <aop:aspect ref="myAscept">
            <!--前置通知-->
            <aop:before method="checkPrivilege" pointcut-ref="pointCut01"></aop:before>
        </aop:aspect>
    </aop:config>      
</aop:config>

后置通知
在原来方法之后执行. 特点: 可以得到被增强方法的返回值 <aop:after-returning …/>

<!--后置通知  -->
<aop:after-returning method="showLog" pointcut-ref="pointCut2" returning="obj"/>

环绕通知
在方法之前和方法之后执行. 特点:可以阻止目标方法执行 <aop:around …/>

//环绕通知(ProceedingJoinPoint 代表目标方法)
    public void showTime(ProceedingJoinPoint joinPoint) throws Throwable {
        //打印系统时间
        System.out.println("调用之前的时间="+System.currentTimeMillis());
        //执行目标方法
        joinPoint.proceed();
        //打印系统时间
        System.out.println("调用之后的时间="+System.currentTimeMillis());

    }

//配置
<!--环绕通知  -->
<aop:around method="showTime" pointcut-ref="pointCut3"/>

异常通知【了解】
方法出现异常执行. 如果方法没有异常,不会执行. 特点:可以获得异常的信息 <aop:after-throwing …/>

增强的方法:
public void afterThrowing(Throwable e){
	System.out.println("异常抛出通知========"+e.getMessage());
}

配置文件:
<aop:after-throwing method="afterThrowing" throwing="e" pointcut-ref="pointCut4"/>

最终通知【了解】
指的是无论是否有异常,总是被执行的。 <aop:after …/>

<!--最终通知  -->
<aop:after method="after" pointcut-ref="pointCut4"/>

定义切面类,在切面增强类上面使用注解 @Aspect并且在切面类中定义切入点方法

@Aspect
public class MyAscept {
    @Before(value = "execution(* com.itheima.dao.impl.AccountDaoImpl.save(..))")
    public void checkPrivilege() {// 通知
        System.out.println("权限的校验...");
    }
}

创建配置文件

<?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">

    <!--注册accountDao-->
    <bean id="accountDao" class="com.itheima.dao.impl.AccountDaoImpl"/>
    <!--注册切面类-->
    <bean id="myAscept" class="com.itheima.aspect.MyAscept"/>
    <!--开启AOP注解-->
    <aop:aspectj-autoproxy/>
</beans>

后置通知

@AfterReturning(value = "execution(* com.itheima.dao.impl.AccountDaoImpl.delete(..))",returning="obj")
public void showLog(Object obj) {
        System.out.println("显示删除之后的日志..." + obj);
}

环绕通知

// 打印时间(环绕通知)
    @Around(value = "execution(* com.itheima.dao.impl.AccountDaoImpl.findAll(..))")
    public void showTime(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("执行之前的时间:" + System.currentTimeMillis());
        //执行findAll
        joinPoint.proceed();
        System.out.println("执行之后的时间:" + System.currentTimeMillis());

    }

异常通知【了解】

 //测试异常通知
    @AfterThrowing(value="execution(* com.itheima.dao.impl.AccountDaoImpl.update(..))",throwing="e")
    public void showException(Throwable e) {
        System.out.println("异常通知...." + e.getMessage());
    }

最终通知【了解】

//测试最终通知
    @After(value = "execution(* com.itheima.dao.impl.AccountDaoImpl.update(..))")
    public void showFinal() {
        System.out.println("最终通知...");
    }

第八章-Spring中的JdbcTemplate 【了解】

  1. JdbcTemplate是Spring里面的持久层一个工具包, 封装了Jdbc
  2. 使用步骤
    • 创建DataSource
    • 创建JDBCTemplate
    • 调用update(), query(), queryForObject()

方式一:
AccountDaoImpl.java

public class AccountDaoImpl implements AccountDao {

	private JdbcTemplate jdbcTemplate;
	
	public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
		this.jdbcTemplate = jdbcTemplate;
	}

	@Override
	public Account findAccountById(Integer id) {
		List<Account> list =  jdbcTemplate.query("select * from account where id = ? ",new AccountRowMapper(),id);
		return list.isEmpty()?null:list.get(0);
	}

	@Override
	public Account findAccountByName(String name) {
		List<Account> list =  jdbcTemplate.query("select * from account where name = ? ",new AccountRowMapper(),name);
		if(list.isEmpty()){
			return null;
		}
		if(list.size()>1){
			throw new RuntimeException("结果集不唯一,不是只有一个账户对象");
		}
		return list.get(0);
	}

	@Override
	public void updateAccount(Account account) {
		jdbcTemplate.update("update account set money = ? where id = ? ",account.getMoney(),account.getId());
	}

}

applicationContext.xml

<!-- 配置一个dao -->
	<bean id="accountDao" class="com.itheima.dao.impl.AccountDaoImpl">
		<!-- 注入jdbcTemplate -->
		<property name="jdbcTemplate" ref="jdbcTemplate"></property>
	</bean>
	
	<!-- 配置一个数据库的操作模板:JdbcTemplate -->
	<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
		<property name="dataSource" ref="dataSource"></property>
	</bean>
	
	<!-- 配置数据源 -->
	<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
		<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
		<property name="url" value="jdbc:mysql:///spring_day04"></property>
		<property name="username" value="root"></property>
		<property name="password" value="123456"></property>
	</bean>

方式二:
AccountDaoImpl.java

public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao {

	@Override
	public Account findAccountById(Integer id) {
		//getJdbcTemplate()方法是从父类上继承下来的。
		List<Account> list = getJdbcTemplate().query("select * from account where id = ? ",new AccountRowMapper(),id);
		return list.isEmpty()?null:list.get(0);
	}

	@Override
	public Account findAccountByName(String name) {
		//getJdbcTemplate()方法是从父类上继承下来的。
		List<Account> list =  getJdbcTemplate().query("select * from account where name = ? ",new AccountRowMapper(),name);
		if(list.isEmpty()){
			return null;
		}
		if(list.size()>1){
			throw new RuntimeException("结果集不唯一,不是只有一个账户对象");
		}
		return list.get(0);
	}

	@Override
	public void updateAccount(Account account) {
		//getJdbcTemplate()方法是从父类上继承下来的。
		getJdbcTemplate().update("update account set money = ? where id = ? ",account.getMoney(),account.getId());
	}
}

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"
    	xsi:schemaLocation="http://www.springframework.org/schema/beans 
    	http://www.springframework.org/schema/beans/spring-beans.xsd">
	
<!-- 配置dao2 -->
<bean id="accountDao" class="com.itheima.dao.impl.AccountDaoImpl">
	<!-- 注入dataSource -->
	<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 配置数据源 -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
	<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
	<property name="url" value="jdbc:mysql:///spring_day04"></property>
		<property name="username" value="root"></property>
		<property name="password" value="123456"></property>
	</bean>
</beans>

第九章-Spring管理事务

概述
由于Spring对持久层的很多框架都有支持 , Hibernate 、 jdbc 、JdbcTemplate , MyBatis 由于使用的框架不同,所以使用事务管理操作API 也不尽相同。 为了规范这些操作, Spring统一定义一个事务的规范 ,这其实是一个接口 。这个接口的名称 : PlatformTrasactionManager.并且它对已经做好的框架都有支持.
如果dao层使用的是JDBC, JdbcTemplate 或者mybatis,那么 可以使用DataSourceTransactionManager 来处理事务
如果dao层使用的是 Hibernate, 那么可以使用HibernateTransactionManager 来处理事务

相关的API
PlatformTransactionManager
平台事务管理器是一个接口,实现类就是Spring真正管理事务的对象。
常用的实现类:
DataSourceTransactionManager :JDBC开发的时候(JDBCTemplate,MyBatis),使用事务管理。
HibernateTransactionManager :Hibernate开发的时候,使用事务管理。
TransactionDefinition
事务定义信息中定义了事务的隔离级别,传播行为,超时信息,只读。TransactionStatus:事务的状态信息
事务状态信息中定义事务是否是新事务,是否有保存点。

编程式(硬编码)事务【了解】

public class JDBCTempleTest {
	 @Test
	 public void fun01() throws PropertyVetoException{
			//1. 创建数据源
			 ComboPooledDataSource dataSource = new ComboPooledDataSource();
			 dataSource.setDriverClass("com.mysql.jdbc.Driver");
			 dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/spring_day03");
			 dataSource.setUser("root");
			 dataSource.setPassword("123456");
			 //2. 创建jdbc模版
			 final JdbcTemplate jdbcTemplate = new JdbcTemplate();
			 jdbcTemplate.setDataSource(dataSource);
			 //3.创建事务管理器
			 DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
			 transactionManager.setDataSource(dataSource);
			 //4.创建事务模版
			 TransactionTemplate transactionTemplate = new TransactionTemplate();
			 transactionTemplate.setTransactionManager(transactionManager);
			 	//4. 进行事务操作
			 transactionTemplate.execute(new TransactionCallback<Object>() {
                @Override
                public Object doInTransaction(TransactionStatus status) {
                    //操作数据库
                    jdbcTemplate.update("update t_account set money = money - ? where name = ?  ", 	100.0,"zs");

                    int i = 1/0;

                    jdbcTemplate.update("update t_account set money = money + ? where name = ?  ", 100.0,"ls");
                    return null;
                }
            });
         }
}

我们项目开发 一般不会使用编程式(硬编码)方式. 一般使用声明式(配置)事务

  • xml方式
  • 注解方式

Spring声明式事务-xml配置方式【重点】
配置事务管理器

<bean id="transactionManager" 		class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource"></property>
</bean>

配置事务建议(事务的规则)

<tx:advice id="adviceId" transaction-manager="transactionManager">
  <!--在tx:advice标签内部 配置事务的属性 -->
  <tx:attributes>
  <!-- 指定方法名称:是业务核心方法 
      read-only:是否是只读事务。默认false,不只读。
      isolation:指定事务的隔离级别。默认值是使用数据库的默认隔离级别。 
      propagation:指定事务的传播行为。
      timeout:指定超时时间。默认值为:-1。永不超时。
      rollback-for:用于指定一个异常,当执行产生该异常时,事务回滚。产生其他异常,事务不回滚。没有默认值,任何异常都回滚。
      no-rollback-for:用于指定一个异常,当产生该异常时,事务不回滚,产生其他异常时,事务回滚。没有默认值,任何异常都回滚。
      -->
      <tx:method name="*" read-only="false" propagation="REQUIRED"/>
      <tx:method name="find*" read-only="true" propagation="SUPPORTS"/>
  </tx:attributes>
</tx:advice>

配置事务的AOP

<aop:config>
	<!-- 定义切入点 ,也就是到底给那些类中的那些方法加入事务的管理 -->
	<aop:pointcut expression="execution(* com.itheima.service.impl.*.*(..))" id="pointCat"/>
	<!-- 让切入点和事务的建议绑定到一起 -->
	<aop:advisor advice-ref="txAdvice" pointcut-ref="pointCat"/>
</aop:config>

spring声明式事务-注解方式【重点】
在applicationContext里面打开注解驱动

<!--,配置事务管理器  -->
	<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource"></property>
	</bean>
	
<!--二配置事务注解  -->
<tx:annotation-driven transaction-manager="transactionManager"/>

在业务逻辑类上面使用注解
@Transactional : 如果在类上声明,那么标记着该类中的所有方法都使用事务管理。也可以作用于方法上, 那么这就表示只有具体的方法才会使用事务。

  • xml方式
    • 优点: 只需要配一次, 全局生效, 容易维护
    • 缺点: 相对注解而言 要麻烦一点
  • 注解方式
    • 优点: 配置简单
    • 缺点: 写一个业务类就配置一次, 事务细节不好处理, 不好维护
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值