• Spring整理


    Spring整理

    IoC概念

    • IoC(Inversion Of Control)控制反转,Spring反向控制应用程序所需要使用的外部资源。举例

    • Spring控制的资源将全部放置在Spring容器中,该容器称为IoC容器

    • IoC是面向对象编程的一种设计原则,可以用来降低代码之间的耦合度

    bean

    • 名称:bean

    • 类型:标签

    • 归属:beans标签

    • 作用:定义spring中的资源,受此标签定义的资源将受到spring控制

    • 基本属性:

      <bean id="userService" name="userService1, userService2" class="com.itheima.service.impl.UserServiceImpl"/>

      id:bean的名称,通过id值获取bean

      class:bean的类型

      name:bean的名称,可以通过name值获取bean,用于多人共同开发时给bean起别名

    set注入(重点)

    • 名称:property

    • 类型:标签

    • 归属:bean标签

    • 作用:使用set方法的形式为bean提供资源

    • 格式:

      <bean>
      <property />
      </bean>
    • 基本属性:

      • 引用类型:自定义类产生的对象,使用ref指定

      • 非引用类型:基本数据类型(int, char,...)和特殊类型String,使用value指定

      <!--非引用类型注入-->
      <property name="propertyName" value="propertyValue" />

      <!--引用类型注入-->
      <property name="propertyName" ref="beanId"/>

    name:对应bean中的属性名,要求该属性必须提供可访问的set方法(严格规范:此名称是set方法对应名称)

    value:设定非引用类型属性对应的值,不能与ref同时使用

    ref:设定引用类型属性对应bean的id ,不能与value同时使用

    集合类型数据注入

    • 名称:array,list,set,map,props

    • 类型:标签

    • 归属:property标签 或 constructor-arg标签

    • 作用:注入集合数据类型属性

    • 格式:

    (1)集合类型数据注入——list

    <!--setAl()-->
    <property name="al">
       <list>
           <value>itheima</value>
           <value>66666</value>
       </list>
    </property>

    (2)集合类型数据注入——props

    <property name="properties">
       <props>
           <prop key="name">itheima666</prop>
           <prop key="value">666666</prop>
       </props>
    </property>

     

    综合案例(重点)(.xml格式)

    案例介绍

    • 使用spring整合mybatis技术,完成账户模块(Account)的基础增删改查功能

    • 账户模块对应字段

      • 编号:id

      • 账户名:name

      • 余额:money

    案例分析

    下图中标红部分需要咱们来实现

    基础准备工作

    • 环境准备:导入Spring坐标,MyBatis坐标,MySQL坐标,Druid坐标

      <dependencies>
         
         <dependency>
             <groupId>org.springframework</groupId>
             <artifactId>spring-context</artifactId>
             <version>5.1.9.RELEASE</version>
         </dependency>
         
         <dependency>
             <groupId>org.mybatis</groupId>
             <artifactId>mybatis</artifactId>
             <version>3.5.3</version>
         </dependency>
         
         <dependency>
             <groupId>mysql</groupId>
             <artifactId>mysql-connector-java</artifactId>
             <version>5.1.47</version>
         </dependency>

         <dependency>
             <groupId>com.alibaba</groupId>
             <artifactId>druid</artifactId>
             <version>1.1.16</version>
         </dependency>
      </dependencies>
    • 业务类与接口准备

      1. 创建数据库表,并制作相应的实体类Account

      2. 定义业务层接口与数据层接口

      3. 在业务层调用数据层接口,并实现业务方法的调用

    • 基础配置文件

      1. jdbc.properties

      2. MyBatis映射配置文件

    整合准备工作

    1.spring配置文件,加上context命名空间,用于加载properties文件

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

    2.开启加载properties文件

    <context:property-placeholder location="classpath:jdbc.properties"/>

    3.配置数据源Druid

    <!--加载druid资源-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
       <property name="driverClassName" value="${jdbc.driver}"/>
       <property name="url" value="${jdbc.url}"/>
       <property name="username" value="${jdbc.username}"/>
       <property name="password" value="${jdbc.password}"/>
    </bean>

    4.定义service层bean,并使用property标签注入dao

    <!--配置service作为spring的bean,注入dao-->
    <bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl">
       <property name="accountDao" ref="accountDao"/>
    </bean>

    5.dao的bean无需定义,MyBatis会自动生成代理对象

     

    整合工作

    1.导入Spring整合MyBatis坐标

    <!--Spring整合MyBatis坐标-->
    <dependency>
       <groupId>org.mybatis</groupId>
       <artifactId>mybatis-spring</artifactId>
       <version>1.3.0</version>
    </dependency>

    <dependency>
       <groupId>org.springframework</groupId>
       <artifactId>spring-jdbc</artifactId>
       <version>5.1.9.RELEASE</version>
    </dependency>

    2.将mybatis配置成spring管理的bean(SqlSessionFactoryBean),并将类型别名交由spring处理

    <!--spring整合mybatis后控制的创建连接用的对象-->
    <bean class="org.mybatis.spring.SqlSessionFactoryBean">
       <property name="dataSource" ref="dataSource"/>
       <property name="typeAliasesPackage" value="com.itheima.domain"/>
    </bean>

    3.通过spring加载mybatis的映射配置文件到spring环境中(映射Mapper扫描工作交由spring处理)

    <!--加载mybatis映射配置的扫描,将其作为spring的bean进行管理-->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
       <property name="basePackage" value="com.itheima.dao"/>
    </bean>

    4.使用spring环境获取业务层bean,执行操作

    public class App {
       public static void main(String[] args) {
           ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
           AccountService accountService = (AccountService) ctx.getBean("accountService");

           //查询
           Account ac = accountService.findById(13);
           System.out.println(ac);

           //保存
           Account account = new Account();
           account.setName("jack");
           account.setMoney(123456.78);
           accountService.save(account);
      }
    }

    注解方式开发

    常用注解(重点)

    启动注解功能

    • 启动注解扫描,加载类中配置的注解项

      <!--注解总开关-->
      <context:component-scan base-package="com.itheima"/>
    • 说明:

      • 在进行包所扫描时,会对配置的包及其子包中所有文件进行扫描

      • 扫描过程是以文件夹递归迭代的形式进行的

      • 扫描过程仅读取合法的java文件

      • 扫描时仅读取spring可识别的注解

      • 扫描结束后会将可识别的有效注解转化为spring对应的资源加入IoC容器

    • 注意:

      • 无论是注解格式还是XML配置格式,最终都是将资源加载到IoC容器中,差别仅仅是数据读取方式不同

      • 从开发效率上来说注解优于XML配置文件

    bean的定义

    • 名称:@Component

    • 类型:类注解

    • 位置:类定义上方

    • 作用:设置该类为spring管理的bean

    • 范例:

      @Component("userService")
      public class UserServiceImpl implements UserService {}

       

      加载第三方资源

      • 名称:@Bean

      • 类型:方法注解

      • 位置:方法定义上方

      • 作用:设置该方法的返回值作为spring管理的bean

      • 范例:

        @Bean("dataSource")
        public DruidDataSource createDataSource() {    return ……;    }

    bean的非引用类型属性注入

    • 名称:@Value

    • 类型:属性注解、方法注解

    • 位置:属性定义上方,set方法定义上方

    • 作用:设置对应属性的值或对方法进行传参

    • 范例:

      @Value("zhangsan")
      private String username;

       

    bean的引用类型属性注入

    • 名称:@Autowired、@Qualifier

    • 类型:属性注解、方法注解

    • 位置:属性定义上方,方法定义上方

    • 作用:设置对应属性的对象或对方法进行引用类型传参

    • 范例:

      @Autowired(required = false)
      private UserDao userDao;

       

    加载properties文件

    • 名称:@PropertySource

    • 类型:类注解

    • 位置:类定义上方

    • 作用:加载properties文件中的属性值

    • 范例:

      @PropertySource(value={"classpath:jdbc.properties","classpath:abc.properties"},ignoreResourceNotFound = true)
      public class ClassName {
          @Value("${propertiesAttributeName}")
          private String attributeName;
      }

       

    纯注解格式

    • 名称:@Configuration、@ComponentScan

    • 类型:类注解

    • 位置:类定义上方

    • 作用:设置当前类为spring核心配置加载类

    • 范例:

      @Configuration
      @ComponentScan("scanPackageName")
      public class SpringConfigClassName{
      }
    • 说明:

      • 核心配合类用于替换spring核心配置文件,此类可以设置空的,不设置变量与属性

      • bean扫描工作使用注解@ComponentScan替代

    AnnotationConfigApplicationContext

    • 加载纯注解格式上下文对象,需要使用AnnotationConfigApplicationContext

    • 当配置类作为 AnnotationConfigApplicationContext 对象创建的参数时,@Configuration注解可以不写

      AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);

    第三方bean配置与管理(重点)

    • 名称:@Import

    • 类型:类注解

    • 位置:类定义上方

    • 作用:导入第三方bean作为spring控制的资源

    • 范例:

      @Configuration
      @Import(OtherClassName.class)
      public class ClassName {
      }

      注解整合MyBatis步骤

      1.修改mybatis外部配置文件格式为注解格式

      public interface AccountDao {
      
          @Insert("insert into account(name,money)values(#{name},#{money})")
          void save(Account account);
      
          @Delete("delete from account where id = #{id} ")
          void delete(Integer id);
      
          @Update("update account set name = #{name} , money = #{money} where id = #{id} ")
          void update(Account account);
      
          @Select("select * from account")
          List<Account> findAll();
      
          @Select("select * from account where id = #{id} ")
          Account findById(Integer id);
      }

      2.业务类使用@Service声明bean,使用@Autowired注入对象

      @Service("accountService")
      public class AccountServiceImpl implements AccountService {
      
          @Autowired
          private AccountDao accountDao;
      }

      3.编写Spring配置类:SpringConfig,并加载properties文件

      @Configuration
      @PropertySource("classpath:jdbc.properties")
      public class SpringConfig {
      }

      4.建立配置文件JDBCConfig与MyBatisConfig类,并将其导入到核心配置类SpringConfig

      数据源配置类:JDBCConfig

      public class JDBCConfig {
      
          @Value("${jdbc.driver}")
          private String driver;
          @Value("${jdbc.url}")
          private String url;
          @Value("${jdbc.username}")
          private String userName;
          @Value("${jdbc.password}")
          private String password;
      
          @Bean(value = "dataSource")
          public DataSource getDataSource(){
              DruidDataSource ds = new DruidDataSource();
              ds.setDriverClassName(driver);
              ds.setUrl(url);
              ds.setUsername(userName);
              ds.setPassword(password);
              return ds;
          }
      }

      MyBatis配置类:MyBatisConfig

      public class MyBatisConfig {
      
          @Bean
          public SqlSessionFactoryBean getSqlSessionFactoryBean(@Autowired DataSource dataSource){
              SqlSessionFactoryBean ssfb = new SqlSessionFactoryBean();
              ssfb.setTypeAliasesPackage("com.itheima.domain");
              ssfb.setDataSource(dataSource);
              return ssfb;
          }
      
          @Bean
          public MapperScannerConfigurer getMapperScannerConfigurer(){
              MapperScannerConfigurer msc = new MapperScannerConfigurer();
              msc.setBasePackage("com.itheima.dao");
              return msc;
          }
      
      }

      5.开启注解扫描,将JDBCConfig与MyBatisConfig类导入到核心配置类SpringConfig中

      @Configuration
      @ComponentScan("com.itheima")
      @PropertySource("classpath:jdbc.properties")
      @Import({JDBCConfig.class,MyBatisConfig.class})
      public class SpringConfig {
      }

      6.使用AnnotationConfigApplicationContext对象加载配置项

      public class App { 
          public static void main(String[] args) {
              ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
              AccountService accountService = (AccountService) ctx.getBean("accountService");
              Account ac = accountService.findById(3);
              System.out.println(ac);
          }
      }

       

    采用注解开发的时候会在testjava下运行测试

    注解整合Junit

    1.导入Spring整合Junit坐标,从Spring5.0以后,要求Junit的版本必须是4.12及以上

    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-test</artifactId>
        <version>5.1.9.RELEASE</version>
    </dependency>

    2.Spring接管Junit的运行权,使用Spring专用的Junit类加载器

    @RunWith(SpringJUnit4ClassRunner.class)

    3.加载Spring配置类

    @ContextConfiguration(classes = SpringConfig.class)
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(classes = SpringConfig.class)
    public class UserServiceTest {
        
        @Test
        public void testSave() {}
    }

    AOP(重点是注解格式)

    AOP概念

    • AOP(Aspect Oriented Programing)面向切面编程,是一种编程范式,隶属于软件工程范畴。

    • AOP基于OOP基础之上进行横向开发,是对 OOP 编程方式的一种补充,并非是取而代之。

    • AOP不是由Spring提出的,最佳开源实现是AspectJ;Spring集成了AspectJ 实现AOP

    AOP作用和优势

    • AOP能够将那些与业务无关,却为业务模块所共同调用的功能,比如

      • 日志记录

      • 性能监控

      • 事务管理

      • 权限控制

        减少系统的重复代码,降低模块之间的耦合度,并有利于将来维护。

    AOP核心概念

    • Joinpoint(连接点):就是方法

    • Pointcut(切入点):就是挖掉共性功能的方法

    • Advice(通知):就是共性功能,最终以一个方法的形式呈现

    • Aspect(切面):就是共性功能与挖的位置的对应关系

    • Target(目标对象):就是挖掉功能的方法对应的类产生的对象,这种对象是无法直接完成最终工作的

    • Weaving(织入):就是将挖掉的功能回填的动态过程

    • Proxy(代理):目标对象无法直接完成工作,需要对其进行功能回填,通过创建原始对象的代理对象实现

    入门案例制作

    下面使用XML方式来开发:

    1.导入aspectj的坐标

    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.9.4</version>
    </dependency>

    2.确认要抽取的功能:并将其制作成方法保存到专用的类中,最后删除原始业务中对应的功能 1591282302976

    3.引入apo命名空间,然后将所有进行AOP操作的资源加载到IoC容器中

    • 引入aop命名空间

      <?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:p="http://www.springframework.org/schema/p"
             xmlns:context="http://www.springframework.org/schema/context"
             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/context
              https://www.springframework.org/schema/context/spring-context.xsd
              http://www.springframework.org/schema/aop
              https://www.springframework.org/schema/aop/spring-aop.xsd">
          <!--3.开启AOP命名空间-->
    • 在applicationContextx.xml中配置userService和通知类AOPAdvice

      <bean id="userService" class="com.itheima.service.impl.UserServiceImpl"/>
      
      <!--2.配置共性功能成为spring控制的资源-->
      <bean id="myAdvice" class="com.itheima.aop.AOPAdvice"/>
    • 对比之前新增的改动 1591282320624

    4.使用配置的方式描述被抽取功能的位置,并描述被抽取功能与对应位置的关系

    <!--aop配置-->
    <aop:config>
        <!--配置切入点-->
        <aop:pointcut id="pt" expression="execution(* *..*(..))"/>
        <!--配置切面-->
        <aop:aspect ref="myAdvice">
            <!--通知与切入点之间的关系-->
            <aop:before method="logAdvice" pointcut-ref="pt"/>
        </aop:aspect>
    </aop:config>

    5.运行App类

    ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
    UserService userService = (UserService) ctx.getBean("userService");
    userService.save();

    AOP配置

    aop:config

    • 名称:aop:config

    • 类型:标签

    • 归属:beans子标签

    • 作用:设置AOP

    • 格式:

      <beans>
          <aop:config>……</aop:config>
          <aop:config>……</aop:config>
      </beans>
    • 说明:一个beans标签中可以配置多个aop:config标签

    aop:aspect

    • 名称:aop:aspect

    • 类型:标签

    • 归属:aop:config标签

    • 作用:设置具体的AOP通知对应的切入点

    • 格式:

      <bean id="myAdvice" class="com.itheima.aop.AOPAdvice"/>
      
      <aop:config>
          <aop:aspect ref="myAdvice">
              <aop:before method="before" pointcut-ref="pt"/>
          </aop:aspect>
      </aop:config>
    • 说明:

      一个aop:config标签中可以配置多个aop:aspect标签

    • 基本属性:

      • ref :通知类的beanId

    aop:pointcut

    • 名称:aop:pointcut

    • 类型:标签

    • 归属:aop:config标签、aop:aspect标签

    • 作用:设置切入点

    • 格式:

      <aop:config>
          <aop:pointcut id="pt" expression="execution(* *..*(..))"/>
          
          <aop:aspect ref="myAdvice">
              <aop:before method="before" pointcut-ref="pt"/>
          </aop:aspect>
      </aop:config>

       

    切入点表达式的组成

    • 切入点表达式是一个快速匹配方法描述的通配格式,类似于正则表达式

      关键字([访问修饰符] 返回值 包名.类名.方法名(参数) [异常名])
      
      #简写方式,省略(访问修饰符、异常名)
      关键字(返回值 包名.类名.方法名(参数))

    关键字:描述表达式的匹配模式(参看关键字列表) 常用execution

    访问修饰符:方法的访问控制权限修饰符,public、 protected、private,可以省略不写

    类名:方法所在的类(此处可以配置接口名称)

    异常:方法定义中指定抛出的异常,可以省略不写

    切入点表达式——逻辑运算符

    • && :连接两个切入点表达式,表示两个切入点表达式同时成立的匹配

    • || :连接两个切入点表达式,表示两个切入点表达式成立任意一个的匹配

    • ! :连接单个切入点表达式,表示该切入点表达式不成立的匹配

    切入点表达式——范例

    execution(* *(..))
    execution(* *..*(..))
    execution(* *..*.*(..))
    execution(public * *..*.*(..))
    execution(public int *..*.*(..))
    execution(public void *..*.*(..))
    execution(public void com..*.*(..)) 
    execution(public void com..service.*.*(..))
    execution(public void com.itheima.service.*.*(..))
    execution(public void com.itheima.service.User*.*(..))
    execution(public void com.itheima.service.*Service.*(..))
    execution(public void com.itheima.service.UserService.*(..))
    execution(public User com.itheima.service.UserService.find*(..))
    execution(public User com.itheima.service.UserService.*Id(..))
    execution(public User com.itheima.service.UserService.findById(..))
    execution(public User com.itheima.service.UserService.findById(int))
    execution(public User com.itheima.service.UserService.findById(int,int))
    execution(public User com.itheima.service.UserService.findById(int,*))
    execution(public User com.itheima.service.UserService.findById(*,int))
    execution(public User com.itheima.service.UserService.findById())
    execution(List com.itheima.service.*Service+.findAll(..))

    通知类型(重点)

    aop:before

    • 名称:aop:before

    • 类型:标签

    • 归属:aop:aspect标签

    • 作用:设置前置通知

    • 格式:

      <aop:aspect ref="adviceId">
          <!--直接配置切入点-->
          <aop:before method="logAdvice" pointcut="execution(* *(..))"/>
      </aop:aspect>
      <aop:aspect ref="adviceId">
          <!--使用公共切入点-->
          <aop:before method="logAdvice" pointcut-ref="pt"/>
      </aop:aspect>

       

    aop:after

    • 名称:aop:after

    • 类型:标签

    • 归属:aop:aspect标签

    • 作用:设置后置通知

    • 格式:

      <aop:aspect ref="adviceId">
          <aop:after method="methodName" pointcut="……"/>
      </aop:aspect>

       

    aop:after-returning

    • 名称:aop:after-returning

    • 类型:标签

    • 归属:aop:aspect标签

    • 作用:设置返回后通知

    • 格式:

      <aop:aspect ref="adviceId">
          <aop:after-returning method="methodName" pointcut="……"/>
         
      </aop:aspect>

       

    aop:after-throwing

    • 名称:aop:after-throwing

    • 类型:标签

    • 归属:aop:aspect标签

    • 作用:设置抛出异常后通知

    • 格式:

      <aop:aspect ref="adviceId">
          <aop:after-throwing method="methodName" pointcut="……" throwing="t"/>
      </aop:aspect>
    • 说明:一个aop:aspect标签中可以配置多个aop:after-throwing标签

    • 基本属性:

      • method :在通知类中设置当前通知类别对应的方法

      • pointcut :设置当前通知对应的切入点表达式,与pointcut-ref属性冲突

      • pointcut-ref :设置当前通知对应的切入点id,与pointcut属性冲突

    aop:around(重点)

    • 名称:aop:around

    • 类型:标签

    • 归属:aop:aspect标签

    • 作用:设置环绕通知

    • 格式:

      <aop:aspect ref="adviceId">
          <aop:around method="methodName" pointcut="……"/>
      </aop:aspect>
    • 说明:一个aop:aspect标签中可以配置多个aop:around标签

    • 基本属性:

      • method :在通知类中设置当前通知类别对应的方法

      • pointcut :设置当前通知对应的切入点表达式,与pointcut-ref属性冲突

      • pointcut-ref :设置当前通知对应的切入点id,与pointcut属性冲突

    环绕通知的开发方式:

    • 环绕通知可以在原始方法的前后分别添加功能,因此必须在在环绕通知中对原始方法进行显式调用

      public Object around(ProceedingJoinPoint pjp) throws Throwable {
          System.out.println("原始方法执行前执行...")
          Object ret = pjp.proceed();
          System.out.println("原始方法执行后执行...")
          return ret;
      }
    • 注意事项

      • 方法的第一个参数必须是ProceedingJoinPoint,通过该对象的proceed()方法,实现对原始方法的调用

      • 使用proceed()方法调用原始方法时,因无法预知原始方法运行过程中是否会出现异常,需要强制抛出Throwable对象,封装原始方法中可能出现的异常信息

    通知中获取数据

    获取参数数据

    第一种方式:

    • 设定通知方法第一个参数为JoinPoint,通过该对象调用getArgs()方法,获取原始方法运行的参数数组

      public void before(JoinPoint jp) {
          //通过JoinPoint参数获取调用原始方法所携带的参数
          Object[] args = jp.getArgs();
          System.out.println("before..." + Arrays.toString(args));
      }
      public class App {
          public static void main(String[] args) {
             	...
              userService.save(666, 888);
          }
      }

    获取返回值数据

    第一种:适用于返回后通知(after-returning)

    • 设定返回值变量名

    • 原始方法

      public int update() {
          System.out.println("user service update running....");
          return 100;
      }
    • AOP配置

      <aop:aspect ref="myAdvice">
          <aop:pointcut id="pt3" expression="execution(* *(..))  "/>
          <aop:after-returning method="afterReturning" pointcut-ref="pt3" returning="ret"/>
      </aop:aspect>
    • 通知类

      public void afterReturning(Object ret) {
          System.out.println("afterReturning..." + ret);
      }
    • 在main方法中执行userService.update(),查看执行结果

    第二种:适用于环绕通知(around)

    • 在通知类的环绕方法中调用原始方法获取返回值

    • 编写带返回值的原始方法

      public int upate() {
          System.out.println("user service running...");
          return 100;
      }
    • AOP配置

      <aop:aspect ref="myAdvice">
          <aop:pointcut id="pt2" expression="execution(* *(..))  "/>
          <aop:around method="around" pointcut-ref="pt2" />
      </aop:aspect>
    • 通知类

      public Object around(ProceedingJoinPoint pjp) throws Throwable {
          Object ret = pjp.proceed();
          System.out.println("around after..." + ret);
          return ret;
      }
    • 在main方法中执行userService.update(),查看执行结果

    通知获取异常数据-视频11

    第一种:通知类的方法中调用原始方法捕获异常,适用于环绕通知(around)

    • 原始方法:模拟抛出除0异常

      public void save() {
          System.out.println("user service running...");
          int i = 1/0;
      }
    • AOP配置

      <aop:aspect ref="myAdvice">
          <aop:pointcut id="pt4" expression="execution(* *(..))  "/>
          <aop:around method="around" pointcut-ref="pt4" />
      </aop:aspect>
    • 通知类

      public Object around(ProceedingJoinPoint pjp) {
          System.out.println("around before...");
          Object ret = null;
          try {
              //对原始方法的调用
              ret = pjp.proceed();
          } catch (Throwable throwable) {
              System.out.println("around...exception...." + throwable.getMessage());
          }
          System.out.println("around after..." + ret);
          return ret;
      }

       

    AOP配置(注解格式)

    AOP注解驱动

    • 名称:@EnableAspectJAutoProxy

    • 类型:注解

    • 位置:Spring注解配置类定义上方

    • 作用:设置当前类开启AOP注解驱动的支持,加载AOP注解

    综合案例

    5.1)案例介绍

    对项目业务层接口执行监控,统计业务层接口的执行效率

    public interface AccountService {
        void save(Account account);
        void delete(Integer id);
        void update(Account account);
        List<Account> findAll();
        Account findById(Integer id);
    }

    5.2)案例分析

    • 测量接口执行效率:接口方法执行前后获取执行时间,求出执行时长

      使用System.currentTimeMillis( )获取系统时间

    • 对项目进行监控:项目中所有查询方法,使用AOP的环绕通知,在proceed()方法执行前后获取系统时间

    5.3)案例制作步骤

    1. 制作AOP环绕通知

    @Component
    @Aspect
    public class RunTimeMonitorAdvice {
        public Object runtimeAround(ProceedingJoinPoint pjp) throws Throwable {
        }
    }
    1. 在通知类RunTimeMonitorAdvice中:定义切入点,绑定到接口上

      //拦截所有的业务层接口中查询操作的执行
      @Pointcut("execution(* com.itheima.service.*Service.find*(..))")
      public void pt(){}
    1. 完善runtimeAround()方法实现,完成测量功能

      @Around("pt()")
      public Object runtimeMonitor(ProceedingJoinPoint pjp) throws Throwable {
          //获取执行签名信息
          Signature signature = pjp.getSignature();
          //通过签名获取执行类型(接口名)
          String targetClass = signature.getDeclaringTypeName();
          //通过签名获取执行操作名称(方法名)
          String targetMethod = signature.getName();
          //获取操作前系统时间beginTime
          long beginTime = System.currentTimeMillis();
          Object ret = pjp.proceed(pjp.getArgs());
          //获取操作后系统时间endTime
          long endTime = System.currentTimeMillis();
          System.out.println(targetClass+" 中 "+targetMethod+" 运行时长 "+(endTime-beginTime)+"ms");
          return ret;
      }
    2. 开启注解驱动支持:@EnableAspectJAutoProxy

      @Configuration
      @ComponentScan("com.itheima")
      @PropertySource("classpath:jdbc.properties")
      @Import({JDBCConfig.class,MyBatisConfig.class})
      @EnableAspectJAutoProxy
      public class SpringConfig {
      }
    3. 运行UserServiceTest单元测试

      //设定spring专用的类加载器
      @RunWith(SpringJUnit4ClassRunner.class)
      //设定加载的spring上下文对应的配置
      @ContextConfiguration(classes = SpringConfig.class)
      public class UserServiceTest {
      
          @Autowired
          private AccountService accountService;
      
          @Test
          public void testFindById(){
              Account ac = accountService.findById(13);
              System.out.println(ac);
          }
      
          @Test
          public void testFindAll(){
              List<Account> list = accountService.findAll();
              System.out.println(list);
          }
      
          @Test
          public void testUpdate() {
              Account ac = accountService.findById(13);
              ac.setMoney(0.01);
              ac.setName("没钱了");
              accountService.update(ac);
          }
      
      }

       

    Spring事务

    事务的作用

    事务特征(ACID)

    • 原子性(Atomicity)指事务是一个不可分割的整体,其中的操作要么全执行或全不执行

    • 一致性(Consistency)事务前后数据的完整性必须保持一致。比如:张三向李四转100元,转账前和转账后的数据是正确状态这叫一致性,如果出现张三转出100元,李四账户没有增加100元这就出现了数据错误,就没有达到一致性。

    • 隔离性(Isolation)事务的隔离性是多个用户并发访问数据库时,数据库为每一个用户开启的事务,不能被其他事务的操作数据所干扰,多个并发事务之间要相互隔离

    • 持久性(Durability)持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响

    四种隔离级

    未提交读(Read Uncommitted) - 允许脏读,会去读到其他事务中未提交的数据

    提交读(Read Committed) ----- 解决了脏读

    可重复读(Repeatable Read) ------消除了不可重复读

    串行读(Serializable) ------- 解决了幻读

    Spring事务核心对象

    Spring提供如下三个接口为业务层提供了整套的事务解决方案

    • 事务定义对象:TransactionDefinition

    • 事务状态:TransactionStatus

    • 平台事务管理器:PlatformTransactionManager

    TransactionDefinition(事务对象)

    此接口定义了事务的基本信息

    • 获取事务定义名称

      String getName()
    • 获取事务的读写属性

      boolean isReadOnly()
    • 获取事务隔离级别

      int getIsolationLevel()
    • 获事务超时时间

      int getTimeout()
    • 获取事务传播行为特征

      int getPropagationBehavior()

    TransactionStatus(事务状态)

    PlatformTransactionManager:事务管理器

    DataSourceTransactionManager(事务管理器的实现类) 适用于Spring JDBC或MyBatis

     

    声明式事务(XML)

    使用声明式事务需要引入tx命名空间:

    <?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:aop="http://www.springframework.org/schema/aop"
           xmlns:tx="http://www.springframework.org/schema/tx"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
            https://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/context
            https://www.springframework.org/schema/context/spring-context.xsd
            http://www.springframework.org/schema/tx
            https://www.springframework.org/schema/tx/spring-tx.xsd
            http://www.springframework.org/schema/aop
            https://www.springframework.org/schema/aop/spring-aop.xsd">

    tx:advice

    • 名称:tx:advice

    • 类型:标签

    • 归属:beans标签

    • 作用:配置事务专属通知类

    • 格式:

      <beans>
          <tx:advice id="txAdvice" transaction-manager="txManager">
          </tx:advice>
      </beans>
    • 基本属性:

      • id :用于配置aop时指定通知类的id

      • transaction-manager :指定事务管理器bean

    tx:attributes

    • 名称:tx:attributes

    • 类型:标签

    • 归属:tx:advice标签

    • 作用:定义通知属性

    • 格式:

      <tx:advice id="txAdvice" transaction-manager="txManager">
          <tx:attributes>
              <tx:method name="*" read-only="false" />
              <tx:method name="get*" read-only="true" />
              <tx:method name="find*" read-only="true" />
           </tx:attributes>
      </tx:advice>

    aop:advisor

    使用aop:advisor在AOP配置中引用事务专属通知类

    <aop:config>
        <aop:pointcut id="pt" expression="execution(* com.itheima.service.*Service.*(..))"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="pt"/>
    </aop:config>

     

    使用XML配置事务

    1. 设置事务管理器

      <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
          <property name="dataSource" ref="dataSource"/>
      </bean>
    2. 配置专用事务通知器

      <!--定义事务管理的通知类-->
      <tx:advice id="txAdvice" transaction-manager="txManager">
          <!--定义控制的事务-->
          <tx:attributes>
              <tx:method name="*" read-only="false"/>
              <tx:method name="get*" read-only="true"/>
              <tx:method name="find*" read-only="true"/>
              <tx:method name="transfer" read-only="false"/>
          </tx:attributes>
      </tx:advice>
    3. AOP配置切面,使用通知器绑定切入点

      <aop:config>
          <aop:pointcut id="pt" expression="execution(* com.itheima.service.*Service.*(..))"/>
          <aop:advisor advice-ref="txAdvice" pointcut-ref="pt"/>
      </aop:config>
    4. 测试转账

      public class App {
          public static void main(String[] args) {
              ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
              AccountService accountService = (AccountService) ctx.getBean("accountService");
              accountService.transfer("tom","itheima",100D);
          }
      }

       

    声明式事务(纯注解驱动)

    pom.xml

     <dependencies>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-context</artifactId>
                <version>5.1.9.RELEASE</version>
            </dependency>
    
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-jdbc</artifactId>
                <version>5.1.9.RELEASE</version>
            </dependency>
    
            <dependency>
                <groupId>org.mybatis</groupId>
                <artifactId>mybatis</artifactId>
                <version>3.5.3</version>
            </dependency>
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>5.1.47</version>
            </dependency>
    
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid</artifactId>
                <version>1.1.16</version>
            </dependency>
    
            <dependency>
                <groupId>org.mybatis</groupId>
                <artifactId>mybatis-spring</artifactId>
                <version>1.3.0</version>
            </dependency>
    
            <dependency>
                <groupId>org.aspectj</groupId>
                <artifactId>aspectjweaver</artifactId>
                <version>1.9.4</version>
            </dependency>
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>4.12</version>
                <scope>test</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-test</artifactId>
                <version>5.1.9.RELEASE</version>
                <scope>test</scope>
            </dependency>
    
        </dependencies>

    jdbc.properties配置文件

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

    Dao包接口SQL语句采用注解格式

    public interface AccountDao {
        /**
         * 入账操作
         * @param name      入账用户名
         * @param money     入账金额
         */
        @Update( "update account set money = money + #{money} where name = #{name}")
        void inMoney(@Param("name") String name, @Param("money") Double money);
    
        /**
         * 出账操作
         * @param name      出账用户名
         * @param money     出账金额
         */
        @Update( "update account set money = money - #{money} where name = #{name}")
        void outMoney(@Param("name") String name, @Param("money") Double money);
    }

    domain包

    public class Account implements Serializable {
    
        private Integer id;
        private String name;
        private Double money;
        省略set方法和toString...
        }

    service接口

    public interface AccountService {
        /**
         * 转账操作
         * @param outName     出账用户名
         * @param inName      入账用户名
         * @param money       转账金额
         */
         //代表切入点和事务的一系列默认值
        @Transactional
    
        public void transfer(String outName,String inName, Double money);
    
    }

    service实现类

    //注解代表配置文件里面的Bean:id
    @Service("accountService")
    public class AccountServiceImpl implements AccountService {
    
        @Autowired
        private AccountDao accountDao;
    
        @Override
        public void transfer(String outName, String inName, Double money) {
            
            accountDao.outMoney(outName, money);
    //        int a = 1 / 0;
            accountDao.inMoney(inName, money);
    
    
        }
    }

    JDBCConfig类

    //扫描配置文件,并且加载
    @Component
    public class JDBCConfig {
        @Value("${jdbc.driver}")
        private String driver;
        @Value("${jdbc.url}")
        private String url;
        @Value("${jdbc.username}")
        private String username;
        @Value("${jdbc.password}")
        private String password;
    
        //连接池
        @Bean("dataSource")
        public DruidDataSource getDataSource() {
    
            DruidDataSource ds = new DruidDataSource();
            ds.setDriverClassName(driver);
            ds.setUrl(url);
            ds.setUsername(username);
            ds.setPassword(password);
    
            return ds;
        }
        //事务管理器
        @Bean
        public PlatformTransactionManager getTransactionManager(DataSource dataSource){
           return new DataSourceTransactionManager(dataSource);
        }
    }

    MyBatisConfig类

    public class MyBatisConfig {
        //定义SqlSessionFactoryBean的时候,dataSource属性是必须指定的,它表示用于连接数据库的数据源
        //spring整合mybatis后控制的创建连接用的对象
        @Bean
        public SqlSessionFactoryBean getSqlSessionFactoryBean(@Autowired DataSource dataSource){
            SqlSessionFactoryBean ssfb=new SqlSessionFactoryBean();
            ssfb.setTypeAliasesPackage("com.itheima.domain");
            ssfb.setDataSource(dataSource);
            return ssfb;
        }
    
        //整合dao接口所有的操作,不用再去为dao配Bean了
        //加载mybatis映射配置的扫描,将其作为spring的bean进行管理
        @Bean
        public MapperScannerConfigurer getMapperScannerConfigurer(){
            MapperScannerConfigurer msc=new MapperScannerConfigurer();
            //basePackage:这个属性就是映射接口的包,这个包里面的所有的接口扫描到
            msc.setBasePackage("com.itheima.dao");
            return msc;
        }
    
    }

    SpringConfig类(重点)

    //纯注解格式
    @Configuration
    //设置当前类为spring核心配置加载类
    @ComponentScan("com.itheima")
    //加载properties文件中的属性值
    @PropertySource("classpath:jdbc.properties")
    //导入写配置的两个类,事务管理器也在JDBCConfig类里面
    @Import({JDBCConfig.class,MyBatisConfig.class})
    //注解 @EnableTransactionManagement 开启事务支持
    @EnableTransactionManagement
    public class SpringConfig {
    }

    主方法测试类UserServiceTest

    //设定Spring专用的类加载器
    @RunWith(SpringJUnit4ClassRunner.class)
    //设定加载Spring上下文对应的配置
    @ContextConfiguration(classes = SpringConfig.class)
    public class UserServiceTest {
        @Autowired
        private AccountService accountService;
    
        @Test
        public void testTransfer(){
            accountService.transfer("Mike","Jock",500D);
        }
    }

     

  • 相关阅读:
    unix网络编程源码编译问题
    ubuntu15.04下安装docker
    hexo博客的相关配置
    hexo的jacman主题配置
    使用github和hexo搭建静态博客
    操作系统简单认识
    github for windows安装以及教程
    编译原理第五单元习题
    python3入门之列表和元组
    Python3入门之软件安装
  • 原文地址:https://www.cnblogs.com/sunhao410526/p/14525853.html
Copyright © 2020-2023  润新知