jdbc-jdbcTemplate-hibernate-jpa-springDataJpa系列(二)

本文涉及的产品
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
简介:

1 前面的文章索引

详见第一篇文章jdbc-jdbcTemplate-hibernate-jpa-springDataJpa系列(一)

这里继续第一篇文章的内容,开始介绍jpa

2 jpa原生开发和事务的使用

2.1 jpa的来源

由于各种orm框架层出不穷,为了统一大家,就出现了jpa这一层接口规范,不同的orm框架都去实现这一规范,然后我们就只关心使用jpa的编程接口来进行编程,不用再关系底层到底使用的是那种orm框架,同时也很容易切换底层所使用的orm框架

2.2 项目地址

2.3 jpa的配置

  • 第一步:就是jpa的核心配置文件 persistence.xml

    默认情况下该配置文件存放的位置是classpath路径下 META-INF/persistence.xml。配置文件的内容如下:

    <persistence-unit name="test" transaction-type="RESOURCE_LOCAL">
        <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
        <properties>
            <property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver" />
            <property name="hibernate.connection.url" value="jdbc:mysql://localhost:3306/test" />
            <property name="hibernate.connection.username" value="root" />
            <property name="hibernate.connection.password" value="ligang" />
            <property name="hibernate.show_sql" value="true" />
            <property name="hibernate.hbm2ddl.auto" value="update" />
        </properties> 
    </persistence-unit>
    

    我们可以看到这个核心配置文件其实就是指明了jpa底层所使用的是何种orm框架,这里称作为provider。然后properties里面的内容,其实都是为provider准备的一些配置信息。

  • 第二步: 根据核心配置文件创建EntityManagerFactory

    EntityManagerFactory entityManagerFactory=Persistence.createEntityManagerFactory("test");
    
  • 第三步:根据EntityManagerFactory创建出EntityManager

    EntityManager entityManager=entityManagerFactory.createEntityManager();
    
  • 第四步:根据EntityManager对实体entity进行增删改查

    entityManager.persist(user)
    

2.4 jpa的几个重要对象说明

建议与Hibenrate的几个重要的原生对象进行对比,地址Hibernate的原生xml方式开发和事务的使用

  • PersistenceProvider接口:

    根据持久化单元名称和配置参数创建出EntityManagerFactory,接口定义如下:

    public interface PersistenceProvider {
        public EntityManagerFactory createEntityManagerFactory(String emName, Map map);
        public EntityManagerFactory createContainerEntityManagerFactory(PersistenceUnitInfo info, Map map);
        //略
    }
    

    jpa仅仅是一层接口规范,不同的底层的实现者提供各自的provider。如hibernate提供的provider实现是org.hibernate.jpa.HibernatePersistenceProvider

  • EntityManagerFactory接口:

    就是EntityManager的工厂。其实可以类似于Hibernate中的SessionFactory。对于Hibernate来说,其实它就是对SessionFactory的封装,Hibernate实现的EntityManagerFactory是EntityManagerFactoryImpl,源码如下:

    public class EntityManagerFactoryImpl implements HibernateEntityManagerFactory {
    
        private final transient SessionFactoryImpl sessionFactory;
        //略
    }
    
  • EntityManager接口:

    能够对实体entity进行增删改查,其实可以类似于Hibernate中的Session。对于Hibernate来说,其实它就是对Session的封装。Hibernate实现的EntityManager是EntityManagerImpl,源码如下:

    public class EntityManagerImpl extends AbstractEntityManagerImpl implements SessionOwner {
    
        protected Session session;
        //略
    }
    
  • EntityTransaction接口:

    jpa定义的事务接口,其实可以类似于Hibernate原生的的Transaction接口。对于Hibernate来说,其实它就是对Transaction的封装。Hibernate实现的EntityTransaction是TransactionImpl,源码如下:

    public class TransactionImpl implements EntityTransaction {
    
        private Transaction tx;
        //略
    }
    

2.5 jpa的使用案例

@Repository
public class JpaDao {
    private EntityManagerFactory entityManagerFactory;
    public JpaDao(){
        entityManagerFactory=Persistence.createEntityManagerFactory("test");
    }
    public EntityManager getEntityManager(){
        return entityManagerFactory.createEntityManager();
    }
}

@Repository
public class UserDao {
    @Autowired
    private JpaDao jpaDao;
    public void save(User user){
        EntityManager entityManager=jpaDao.getEntityManager();
        EntityTransaction tx=null;
        try {
            tx=entityManager.getTransaction();
            tx.begin();
            entityManager.persist(user);
            tx.commit();
        } catch (Exception e) {
            if(tx!=null){
                tx.rollback();
            }
        }finally{
            entityManager.close();
        }
    }
}

我们可以看到,上述的save过程和Hibernate的过程非常相似,只不过把Hibernate的那一套对象换成了对应的jpa对象。

建议与Hibenrate的使用过程进行对比,地址Hibernate的原生xml方式开发和事务的使用

3 jpa与spring的集成

上述jpa原生方式,还没有使用dataSource,为了引入dataSource来更好的管理数据库连接,为了简化jpa的配置,同时可以去掉jpa的核心配置文件,spring针对原生的jpa做了自己的集成工作。

3.1 项目地址

3.2 配置

  • 第一步:配置数据库连接池dataSource

    <bean id="dataSource"   
        class="com.mchange.v2.c3p0.ComboPooledDataSource"   
        destroy-method="close">   
        <property name="driverClass">   
            <value>${jdbc.driverClass}</value>   
        </property>   
        <property name="jdbcUrl">   
            <value>${jdbc.url}</value>   
        </property>   
        <property name="user">   
            <value>${jdbc.user}</value>   
        </property>   
        <property name="password">   
            <value>${jdbc.password}</value>   
        </property>   
        <!--连接池中保留的最小连接数。-->   
        <property name="minPoolSize">   
            <value>${jdbc.minPoolSize}</value>   
        </property>   
        <!--连接池中保留的最大连接数。Default: 15 -->   
        <property name="maxPoolSize">   
            <value>${jdbc.maxPoolSize}</value>   
        </property>   
        <!--初始化时获取的连接数,取值应在minPoolSize与maxPoolSize之间。Default: 3 -->   
        <property name="initialPoolSize">   
            <value>${jdbc.initialPoolSize}</value>   
        </property>   
    </bean>
    
  • 第二步:配置entityManagerFactory

    <bean id="entityManagerFactory"     class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="jpaVendorAdapter" ref="jpaVendorAdapter"/>
        <property name="packagesToScan" value="com.demo.entity"/>
    </bean>
    

    其中的jpaVendorAdapter其实是收集配置参数,然后告诉LocalContainerEntityManagerFactoryBean所使用的PersistenceProvider,稍后详细分析,配置如下:

    <bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
        <property name="database" value="MYSQL"/>
        <property name="showSql" value="true"/>
        <property name="generateDdl" value="true"/>
        <property name="databasePlatform" value="org.hibernate.dialect.MySQLDialect"/>
    </bean>
    
  • 第三步:配置事务管理器JpaTransactionManager

    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory"></property>
    </bean>
    

    JpaTransactionManager是依赖于entityManagerFactory的

  • 第四步:启动@Transactional注解的处理器

    <tx:annotation-driven proxy-target-class="true" transaction-manager="transactionManager"/>
    

    处理器依赖于transactionManager的

3.3 使用案例

@Repository
public class UserDao {

    @PersistenceContext
    private EntityManager entityManager;

    @Transactional
    public void save(User user){
        entityManager.persist(user);
    }
}

使用@PersistenceContext注解来获取entityManagerFactory创建的EntityManager对象,然后使用EntityManager进行增删改查

3.4 原理分析

3.4.1 如何创建EntityManagerFactory

我们可以看到spring是使用了一个工厂bean LocalContainerEntityManagerFactoryBean来创建entityManagerFactory。虽然配置的是一个工厂bean,但是容器在根据id来获取bean的时候,返回的是该工厂bean所创建的实体,即LocalContainerEntityManagerFactoryBean所创建的EntityManagerFactory。

spring创建EntityManagerFactory有2中方式,如下图所示: 
spring创建EntityManagerFactory有2中方式

  • LocalEntityManagerFactoryBean

    它分成2种情况来创建

    • 方式1:当LocalEntityManagerFactoryBean本身指定了PersistenceProvider,就使用该PersistenceProvider来创建EntityManagerFactory,详见上文的PersistenceProvider接口定义

    • 方式2:使用上文jpa原生方式的:

      EntityManagerFactory entityManagerFactory=Persistence.createEntityManagerFactory("test");
      

    LocalEntityManagerFactoryBean的源码如下:

    public class LocalEntityManagerFactoryBean extends AbstractEntityManagerFactoryBean {
    
        @Override
        protected EntityManagerFactory createNativeEntityManagerFactory() 
                throws PersistenceException {
            PersistenceProvider provider = getPersistenceProvider();
            if (provider != null) {
                // Create EntityManagerFactory directly through PersistenceProvider.
                EntityManagerFactory emf = provider.createEntityManagerFactory
                    (getPersistenceUnitName(), getJpaPropertyMap());
                return emf;
            }
            else {
                // Let JPA perform its standard PersistenceProvider autodetection.
                return Persistence.createEntityManagerFactory(
                    getPersistenceUnitName(), getJpaPropertyMap());
            }
        }
        //略了部分内容
    }
    

    我们再详细了解下下面的这个过程:

    EntityManagerFactory entityManagerFactory=Persistence.createEntityManagerFactory("test");
    

    它其实也是先获取所有的PersistenceProvider,然后遍历PersistenceProvider来创建EntityManagerFactory,源码如下:

    public static EntityManagerFactory createEntityManagerFactory(String            
                    persistenceUnitName, Map properties) {
        EntityManagerFactory emf = null;
        List<PersistenceProvider> providers = getProviders();
        for ( PersistenceProvider provider : providers ) {
            emf = provider.createEntityManagerFactory( persistenceUnitName, properties );
            if ( emf != null ) {
                break;
            }
        }
        if ( emf == null ) {
            throw new PersistenceException( "No Persistence provider 
                for EntityManager named " + persistenceUnitName );
        }
        return emf;
    }
    

    那它是如何来获取所有的PersistenceProvider的呢?

    这里就用到了java的SPI机制(Service Provider Interfaces)

    如下简单说明下,详细内容可以自行搜索:

    • jpa定义了PersistenceProvider接口
    • Hibernate要实现这个接口,在hibernate-entitymanager这个jar包中,在META-INF/services文件夹下,会有一个以PersistenceProvider接口全称命名的文件,如下图所示:

    PersistenceProvider的SPI机制

    文件里面的内容就是该接口对应的实现类,内容如下:

    org.hibernate.jpa.HibernatePersistenceProvider
    # The deprecated provider, logs warnings when used.
    org.hibernate.ejb.HibernatePersistence
    

    这就很容易方便jpa来寻找PersistenceProvider所有的实现类

  • LocalContainerEntityManagerFactoryBean

    它创建一个PersistenceProvider需要以下几个重要的属性元素

    • jpaVendorAdapter

      它的主要作用就是收集一些配置信息,并且提供一个PersistenceProvider。接口定义如下:

      public interface JpaVendorAdapter {
          PersistenceProvider getPersistenceProvider();
          Map<String, ?> getJpaPropertyMap();
          //略
      }
      

      以HibernateJpaVendorAdapter为例,在它初始化的时候就会创建出HibernatePersistenceProvider,如下:

      public class HibernateJpaVendorAdapter extends AbstractJpaVendorAdapter
          private final PersistenceProvider persistenceProvider;
          public HibernateJpaVendorAdapter() {
              PersistenceProvider providerToUse;
              try {
                  ClassLoader cl = HibernateJpaVendorAdapter.class.getClassLoader();
                  Class<?> hibernatePersistenceProviderClass = cl.loadClass
                      ("org.hibernate.jpa.HibernatePersistenceProvider");
                  providerToUse = (PersistenceProvider) hibernatePersistenceProviderClass.newInstance();
              }
              this.persistenceProvider = providerToUse;
              //略
          }
      }
      
    • PersistenceProvider :

      它的来历至少有两种方式:

      • 在配置LocalContainerEntityManagerFactoryBean的时候,直接配置一个PersistenceProvider
      • 如果没有进行上述配置,则使用上述的jpaVendorAdapter指定的PersistenceProvider
    • dataSource

      不再像原生的jpa那样直接使用核心配置文件中的连接信息(这些连接信息是配置给PersistenceProvider的)

    • packagesToScan等信息

      用于指定注解式实体所在的包路径,和dataSource一样都作为配置信息,最终都反应在PersistenceProvider创建的EntityManagerFactory上了

3.4.2 如何获取EntityManager

我们看到在例子中,是通过使用@PersistenceContext来获取一个EntityManager的,我们知道这个EntityManager就是通过我们配置的上述EntityManagerFactory来创建的,但具体是一个什么过程呢?

突然发现这一块源码内容也好多,主要是PersistenceAnnotationBeanPostProcessor这个处理器在处理

@PersistenceContext注解和我们常用的@Autowired是类似的,他们都是实现依赖注入的,内容还是很多,所以打算之后另开一篇博客,单独讲解这类依赖注入的注解

至此我们就大致了解jpa与Spring是怎么集成的,总之还是通过PersistenceProvider和配置信息来创建出EntityManagerFactory。

3.4.3 事务过程是怎么实现的

过程比较复杂,总之原理还是使用ThreadLocal机制

@PersistenceContext
private EntityManager entityManager;

@Transactional
public void save(User user){
    entityManager.persist(user);
    throw new RuntimeException();
}
  • 1 在执行save方法之前,使用了事务管理器JpaTransactionManager执行了开启事务的操作

    • 1.1 创建了一个EntityManager对象,以Hibernate来说就是创建了EntityManagerImpl(同时内部创建了Session和TransactionImpl),然后通过TransactionImpl开启事务
    • 1.2 将创建的EntityManagerImpl对象绑定到当前线程
  • 2 通过注入进来的entityManager来保存user

    这个注入进来的entityManager仅仅是一个空壳子,是一个代理对象,它会获取当前线程绑定的上述EntityManagerImpl对象,来实现保存user

  • 3 一旦出现异常,则使用1.1步骤中创建的EntityManagerImpl中的事务TransactionImpl来实现回滚

总之,保证了业务代码和事务代码使用的是同一个EntityManager对象对象,所以可以正常回滚。 
总之使用@Transactional注解式的事务,总要使用ThreadLocal模式来保证业务代码和事务代码中的使用的connection是一致的这一原则。

4 多数据源下jpa与spring集成开发和事务的使用

4.1 项目地址

4.2 配置

4.2.1 配置两个数据库连接池dataSource

<bean id="dataSource1"   
    class="com.mchange.v2.c3p0.ComboPooledDataSource"   
    destroy-method="close">   
    <property name="driverClass">   
        <value>${jdbc1.driverClass}</value>   
    </property>   
    <property name="jdbcUrl">   
        <value>${jdbc1.url}</value>   
    </property>   
    //略,见项目中的配置
</bean>

 <!-- 配置数据源 -->
 <bean id="dataSource2"   
    class="com.mchange.v2.c3p0.ComboPooledDataSource"   
    destroy-method="close">   
    <property name="driverClass">   
        <value>${jdbc2.driverClass}</value>   
    </property>   
    <property name="jdbcUrl">   
        <value>${jdbc2.url}</value>   
    </property>   
    //略,见项目中的配置 
</bean>

记得根据配置创建相应的数据库和表

4.2.2 配置2个entityManagerFactory

<bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
    <property name="database" value="MYSQL"/>
    <property name="showSql" value="true"/>
    <property name="generateDdl" value="true"/>
    <property name="databasePlatform" value="org.hibernate.dialect.MySQLDialect"/>
</bean>

<bean id="entityManagerFactory1" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="dataSource" ref="dataSource1"/>
    <property name="jpaVendorAdapter" ref="jpaVendorAdapter"/>
    <property name="packagesToScan" value="com.demo.entity"/>
</bean>

<bean id="entityManagerFactory2" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="dataSource" ref="dataSource2"/>
    <property name="jpaVendorAdapter" ref="jpaVendorAdapter"/>
    <property name="packagesToScan" value="com.demo.entity"/>
    <property name="persistenceUnitName" value="test2"/>
</bean>

这两个entityManagerFactory使用不同的dataSource,各自有一个persistenceUnitName名字(持久化单元的名字),分别叫"test1"和"test2”。在上文中,并没有配置persistenceUnitName,采用默认值"default”

4.2.3 配置2个事务管理器

<bean id="transactionManager1" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactory1"></property>
</bean>

<bean id="transactionManager2" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactory2"></property>
</bean>

4.2.4 开启@Transactional的处理器

<tx:annotation-driven proxy-target-class="true"/>

4.3 使用方式

@Repository
public class UserDao {

    @PersistenceContext(unitName="test1")
    private EntityManager entityManager;
    @PersistenceContext(unitName="test2")
    private EntityManager entityManagerTest2;

    @Transactional("transactionManager1")
    public void save(User user){
        entityManager.persist(user);
    }
    @Transactional("transactionManager2")
    public void save2(User user){
        entityManagerTest2.persist(user);
    }
}

@PersistenceContext(unitName=“test1”)表示使用persistenceUnitName=“test1"的entityManagerFactory来创建EntityManager,同理@PersistenceContext(unitName=“test2”)也一样。

如果有多个entityManagerFactory,但是只使用@PersistenceContext没有指定unitName,则会报错,spring不知道该选择哪一个,所以需要指定unitName的名字

@Transactional(“transactionManager1”)表示使用id=“transactionManager1"的JpaTransactionManager来作为事务管理器 
同理@Transactional(“transactionManager2”)也一样。

多数据源就不再详细说明了

5 spring-data-jpa的开发和事务的使用

5.1 背景

引用IBM的一篇文章使用 Spring Data JPA 简化 JPA 开发

Spring 对 JPA 的支持已经非常强大,开发者只需关心核心业务逻辑的实现代码,无需过多关注 EntityManager 的创建、事务处理等 JPA 相关的处理,这基本上也是作为一个开发框架而言所能做到的极限了。然而,Spring 开发小组并没有止步,他们再接再厉,于最近推出了 Spring Data JPA 框架,主要针对的就是 Spring 唯一没有简化到的业务逻辑代码,至此,开发者连仅剩的实现持久层业务逻辑的工作都省了,唯一要做的,就只是声明持久层的接口,其他都交给 Spring Data JPA 来帮你完成

至此,读者可能会存在一个疑问,框架怎么可能代替开发者实现业务逻辑呢?毕竟,每一个应用的持久层业务甚至领域对象都不尽相同,框架是怎么做到的呢?其实这背后的思想并不复杂,比如,当你看到 UserDao.findUserById() 这样一个方法声明,大致应该能判断出这是根据给定条件的 ID 查询出满足条件的 User 对象。Spring Data JPA 做的便是规范方法的名字,根据符合规范的名字来确定方法需要实现什么样的逻辑

这篇文章的内容已经很详细了,这里就仅仅详细地列出配置,真正跑起来

5.2 配置

有了前面的基础后,就非常简单了

5.2.1 配置dataSource

<bean id="dataSource"   
    class="com.mchange.v2.c3p0.ComboPooledDataSource"   
    destroy-method="close">   
    <property name="driverClass">   
        <value>${jdbc.driverClass}</value>   
    </property>   
    <property name="jdbcUrl">   
        <value>${jdbc.url}</value>   
    </property>   
    //略   
</bean>

5.2.2 配置entityManagerFactory

<bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
    <property name="database" value="MYSQL"/>
    <property name="showSql" value="true"/>
    <property name="generateDdl" value="true"/>
    <property name="databasePlatform" value="org.hibernate.dialect.MySQLDialect"/>
</bean>

<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="dataSource" ref="dataSource"/>
    <property name="jpaVendorAdapter" ref="jpaVendorAdapter"/>
    <property name="packagesToScan" value="com.demo.entity"/>
</bean>

5.2.3 配置transactionManager

<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactory"></property>
</bean>

5.2.4 开启@Transactional的处理器

<tx:annotation-driven proxy-target-class="true" transaction-manager="transactionManager"/>

5.2.5 配置要扫描的dao的路径

<jpa:repositories base-package="com.demo.dao"/>

使用jpa命名空间的元素,需要加入如下jpa的约束配置:

<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans" 
    xmlns:jpa="http://www.springframework.org/schema/data/jpa"
    //略
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/data/jpa
    http://www.springframework.org/schema/data/jpa/spring-jpa-1.2.xsd">

我们之前需要自己手写一个UserDao,自己实现相应的方法,注入EntityManager,然后进行增删改查,现在不需要了,只需定义一个接口即可

public interface UserDao extends CrudRepository<User,Long>{

}

CrudRepository 类型中的前者User表示User实体,后者Long表示User实体的主键类型

5.3 使用过程

我们只需定义上述一个接口,即可在别的地方注入使用UserDao,来进行增删改查,如下:

@Autowired
private UserDao userDao;

@Test
public void testSaveUser(){
    User user=new User();
    user.setName("王五");
    user.setAge(22);
    userDao.save(user);
}

5.4 spring-data-jpa实现的功能介绍

上面仅仅是一个简单的使用例子,更多复杂的例子,见IBM的一篇文章使用 Spring Data JPA 简化 JPA 开发

相关实践学习
基于CentOS快速搭建LAMP环境
本教程介绍如何搭建LAMP环境,其中LAMP分别代表Linux、Apache、MySQL和PHP。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
10天前
|
SQL Java 数据库连接
jpa、hibernate、spring-data-jpa、jdbcTemplate
jpa、hibernate、spring-data-jpa、jdbcTemplate
|
10月前
|
SQL 存储 Java
Hibernate
Hibernate
48 0
|
存储 SQL 缓存
JPA 之 Hibernate EntityManager 专题
JPA 之 Hibernate EntityManager 专题
559 0
JPA 之 Hibernate EntityManager 专题
|
SQL 缓存 安全
SpringJDBC、Hibernate、MyBatis
SpringJDBC、Hibernate、MyBatis
SpringJDBC、Hibernate、MyBatis
|
消息中间件 前端开发 NoSQL
SpringMVC(三、JDBCTemplate)
Spring框架对JDBC进行封装,使用JdbcTemplate方便实现对数据库操作。 Spring MVC 的拦截器(interceptor)类似于 Servlet 开发中的过滤器 Filter,用于对处理器进行预处理和后处理。 将拦截器按一定的顺序联结成一条链,这条链称为拦截器链(Interceptor Chain)。在访问被拦截的方 法或字段时,拦截器链中的拦截器就会按其之前定义的顺序被调用。拦截器也是AOP思想的具体实现。
163 0
SpringMVC(三、JDBCTemplate)
|
SQL Java 数据库连接