zoukankan      html  css  js  c++  java
  • 阶段六模块二 Spring 学习笔记

    Spring概述

    Spring是什么

    Spring是分层的 Java SE/EE应用 full-stack(全栈式) 轻量级开源框架。

    提供了表现层 SpringMVC和持久层 Spring JDBC Template以及 业务层 事务管理等众多的企业级应用技术,还能整合开源世界众多著名的第三方框架和类库,逐渐成为使用最多的Java EE 企业应用开源框架。

    两大核心:以 IOC(Inverse Of Control:控制反转)和 AOP(Aspect Oriented Programming:面向切面编程)为内核。

    Spring优势

    1)方便解耦,简化开发
      Spring就是一个容器,可以将所有对象创建和关系维护交给Spring管理
      什么是耦合度?对象之间的关系,通常说当一个模块(对象)更改时也需要更改其他模块(对象),这就是耦合,耦合度过高会使代码的维护成本增加。要尽量解耦
    2)AOP编程的支持
      Spring提供面向切面编程,方便实现程序进行权限拦截,运行监控等功能。
    3)声明式事务的支持
      通过配置完成事务的管理,无需手动编程
    4)方便测试,降低JavaEE API的使用
      Spring对Junit4支持,可以使用注解测试
    5)方便集成各种优秀框架
      不排除各种优秀的开源框架,内部提供了对各种优秀框架的直接支持

    Spring体系结构

     IOC

    控制反转(Inverse Of Control)不是什么技术,而是一种设计思想。它的目的是指导我们设计出更加松耦合的程序。

    控制:在java中指的是对象的控制权限(创建、销毁)
    反转:指的是对象控制权由原来 由开发者在类中手动控制 反转到 由Spring容器控制

    Spring基于的开发步骤

    1. 导入坐标
    2. 创建Bean
    3. 创建applicationContext.xml
    4. 在配置文件中进行Bean配置
    5. 创建ApplicationContext对象,执行getBean

    Spring API继承体系介绍

     BeanFactory

    BeanFactory是 IOC 容器的核心接口,它定义了IOC的基本功能。

    特点:在第一次调用getBean()方法时,创建指定对象的实例

    ApplicationContext

    代表应用上下文对象,可以获得spring中IOC容器的Bean对象。

    特点:在spring容器启动时,加载并创建所有对象的实例

    常用实现类

    1. ClassPathXmlApplicationContext
       它是从类的根路径下加载配置文件 推荐使用这种。
      
    2. FileSystemXmlApplicationContext
       它是从磁盘路径上加载配置文件,配置文件可以在磁盘的任意位置。
      
    3. AnnotationConfigApplicationContext
       当使用注解配置容器对象时,需要使用此类来创建 spring 容器。它用来读取注解。

    ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");

    常用方法

    1. Object getBean(String name);
      根据Bean的id从容器中获得Bean实例,返回是Object,需要强转。
    2. <T> T getBean(Class<T> requiredType);
      根据类型从容器中匹配Bean实例,当容器中相同类型的Bean有多个时,则此方法会报错。
    3. <T> T getBean(String name,Class<T> requiredType);
      根据Bean的id和类型获得Bean实例,解决容器中相同类型Bean有多个情况。

    Bean标签基本配置

    <bean id="" class=""></bean>
    * 用于配置对象交由Spring来创建。
    * 基本属性:
      id:Bean实例在Spring容器中的唯一标识
      class:Bean的全限定名
    * 默认情况下它调用的是类中的 无参构造函数,如果没有无参构造函数则不能创建成功。

    Bean标签范围配置

    <bean id="" class="" scope=""></bean>

    scope属性指对象的作用范围,取值如下:

    1. 当scope的取值为singleton时
       Bean的实例化个数:1个
          Bean的实例化时机:当Spring核心文件被加载时,实例化配置的Bean实例
          Bean的生命周期:
            对象创建:当应用加载,创建容器时,对象就被创建了
            对象运行:只要容器在,对象一直活着
            对象销毁:当应用卸载,销毁容器时,对象就被销毁了
    2. 当scope的取值为prototype时
       Bean的实例化个数:多个
          Bean的实例化时机:当调用getBean()方法时实例化Bean
          Bean的生命周期:
             对象创建:当使用对象时,创建新的对象实例
             对象运行:只要对象在使用中,就一直活着
             对象销毁:当对象长时间不用时,被 Java 的垃圾回收器回收了

    Bean生命周期配置

    <bean id="" class="" scope="" init-method="" destroy-method=""></bean>
    * init-method:指定类中的初始化方法名称
    * destroy-method:指定类中销毁方法名称

    Bean实例化三种方式

    无参构造方法实例化

    它会根据默认无参构造方法来创建类对象,如果bean中没有默认无参构造函数,将会创建失败

    <bean id="userDao" class="com.lagou.dao.impl.UserDaoImpl"/>

    工厂静态方法实例化

    <bean id="userDao" class="com.lagou.factory.StaticFactoryBean" factory-method="createUserDao" />

    工厂普通方法实例化

    <bean id="dynamicFactoryBean" class="com.lagou.factory.DynamicFactoryBean"/>
    <bean id="userDao" factory-bean="dynamicFactoryBean" factory-
    method="createUserDao"/>

    Bean依赖注入概述

    依赖注入 DI(Dependency Injection):它是 Spring 框架核心 IOC 的具体实现。
    在编写程序时,通过控制反转,把对象的创建交给了 Spring,但是代码中不可能出现没有依赖的情况。IOC 解耦只是降低他们的依赖关系,但不会消除。例如:业务层仍会调用持久层的方法。
    那这种业务层和持久层的依赖关系,在使用 Spring 之后,就让 Spring 来维护了。简单的说,就是通过框架把持久层对象传入业务层,而不用我们自己去获取。

    Bean依赖注入方式

    构造方法

    public class UserServiceImpl implements UserService {
      private UserDao userDao;
      public UserServiceImpl(UserDao userDao) {
        this.userDao = userDao;
     }
      @Override
      public void save() {
        userDao.save();
     }
    }

    配置Spring容器调用有参构造时进行注入

    <bean id="userDao" class="com.lagou.dao.impl.UserDaoImpl"/>
    <bean id="userService" class="com.lagou.service.impl.UserServiceImpl">
      <!--<constructor-arg index="0" type="com.lagou.dao.UserDao" ref="userDao"/>-
    ->
      <constructor-arg name="userDao" ref="userDao"/>
    </bean>

    set方法

    在UserServiceImpl中创建set方法

    public class UserServiceImpl implements UserService {
      private UserDao userDao;
      public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
     }
      @Override
      public void save() {
        userDao.save();
     }
    }

    配置Spring容器调用set方法进行注入

    <bean id="userDao" class="com.lagou.dao.impl.UserDaoImpl"/>
    <bean id="userService" class="com.lagou.service.impl.UserServiceImpl">
      <property name="userDao" ref="userDao"/>
    </bean>

    P命名空间注入

    P命名空间注入本质也是set方法注入,但比起上述的set方法注入更加方便,主要体现在配置文件中,如下:

    首先,需要引入P命名空间:

    xmlns:p="http://www.springframework.org/schema/p"

    其次,需要修改注入方式:

    <bean id="userDao" class="com.lagou.dao.impl.UserDaoImpl"/>
    <bean id="userService" class="com.lagou.service.impl.UserServiceImpl" p:userDao-ref="userDao"/>

    Bean依赖注入的数据类型

    1. 普通数据类型

    2. 引用数据类型

    3. 集合数据类型

    注入普通数据类型

    <bean id="user" class="com.lagou.domain.User">
      <property name="username" value="jack"/>
      <property name="age" value="18"/>
    </bean>

    注入集合数据类型

    1)List集合注入

    <bean id="user" class="com.lagou.domain.User">
      <property name="username" value="jack"/>
      <property name="age" value="18"/>
    </bean>
    <bean id="userDao" class="com.lagou.dao.impl.UserDaoImpl">
      <property name="list">
        <list>
          <value>aaa</value>
          <ref bean="user"></ref>
        </list>
      </property>
    </bean>

    2)Set集合注入

    <bean id="user" class="com.lagou.domain.User">
      <property name="username" value="jack"/>
      <property name="age" value="18"/>
    </bean>
    <bean id="userDao" class="com.lagou.dao.impl.UserDaoImpl">
      <property name="set">
        <list>
          <value>bbb</value>
          <ref bean="user"></ref>
        </list>
      </property>
    </bean>

    3)Array数组注入

    <bean id="user" class="com.lagou.domain.User">
      <property name="username" value="jack"/>
      <property name="age" value="18"/>
    </bean>
    <bean id="userDao" class="com.lagou.dao.impl.UserDaoImpl">
      <property name="array">
        <array>
          <value>ccc</value>
          <ref bean="user"></ref>
        </array>
      </property>
    </bean>

    4)Map集合注入

    <bean id="user" class="com.lagou.domain.User">
      <property name="username" value="jack"/>
      <property name="age" value="18"/>
    </bean>
    <bean id="userDao" class="com.lagou.dao.impl.UserDaoImpl">
      <property name="map">
        <map>
          <entry key="k1" value="ddd"/>
          <entry key="k2" value-ref="user"></entry>
        </map>
      </property>
    </bean>

    5)Properties配置注入

    <bean id="userDao" class="com.lagou.dao.impl.UserDaoImpl">
      <property name="properties">
        <props>
          <prop key="k1">v1</prop>
          <prop key="k2">v2</prop>
          <prop key="k3">v3</prop>
        </props>
      </property>
    </bean>

    配置文件模块化

    实际开发中,Spring的配置内容非常多,这就导致Spring配置很繁杂且体积很大,所以,可以将部分配置拆解到其他配置文件中,也就是所谓的配置文件模块化

    1)并列的多个配置文件

    ApplicationContext act = new ClassPathXmlApplicationContext("beans1.xml","beans2.xml","...");

    2)主从配置文件

    <import resource="applicationContext-xxx.xml"/>

    注意:

    • 同一个xml中不能出现相同名称的bean,如果出现会报错
    • 多个xml如果出现相同名称的bean,不会报错,但是后加载的会覆盖前加载的bean

    知识小结

    Spring的重点配置

    <bean>标签:创建对象并放到spring的IOC容器
       id属性:在容器中Bean实例的唯一标识,不允许重复
       class属性:要实例化的Bean的全限定名
       scope属性:Bean的作用范围,常用是Singleton(默认)和prototype
     
    <constructor-arg>标签:属性注入
      name属性:属性名称
       value属性:注入的普通属性值
       ref属性:注入的对象引用值

    <property>标签:属性注入
       name属性:属性名称
       value属性:注入的普通属性值
       ref属性:注入的对象引用值
      <list>
         <set>
         <array>
            <map>
            <props>
    <import>标签:导入其他的Spring的分文件

    Spring注解开发

    Spring是轻代码而重配置的框架,配置比较繁重,影响开发效率,所以注解开发是一种趋势,注解代替xml配置文件可以简化配置,提高开发效率

    Spring常用注解

     说明:

    JDK11以后完全移除了javax扩展导致不能使用@resource注解。

    使用注解进行开发时,需要在applicationContext.xml中配置组件扫描,作用是指定哪个包及其子包下的Bean需要进行扫描以便识别使用注解配置的类、字段和方法。

    <!--注解的组件扫描-->
    <context:component-scan base-package="com.lagou"></context:component-scan>

    Spring新注解

    * 非自定义的Bean的配置:<bean>

    * 加载properties文件的配置:<context:property-placeholder>

    * 组件扫描的配置:<context:component-scan>

    * 引入其他文件:<import>

     Spring整合Junit

    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(classes = {SpringConfig.class})
    public class SpringJunitTest {
     
     @Autowired
      private AccountService accountService;
     
      //测试查询
      @Test
      public void testFindById() {
        Account account = accountService.findById(3);
        System.out.println(account);
     }
    }

    AOP

    常用的动态代理技术

    • JDK 代理 : 基于接口的动态代理技术·:利用拦截器(必须实现invocationHandler)加上反射机制生成一个代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理,从而实现方法增强
    • CGLIB代理:基于父类的动态代理技术:动态生成一个要代理的子类,子类重写要代理的类的所有不是final的方法。在子类中采用方法拦截技术拦截所有的父类方法的调用,顺势织入横切逻辑,对方法进行增强

     JDK动态代理方式

    @Component
        public class JdkProxyFactory {
            @Autowired
            private AccountService accountService;
    
            @Autowired
            private TransactionManager transactionManager;
    
            public AccountService createAccountServiceJdkProxy() {
                AccountService accountServiceProxy = null;
                accountServiceProxy = (AccountService) Proxy.newProxyInstance(accountService.getClass().getClassLoader(),
                        accountService.getClass().getInterfaces(),
                        new InvocationHandler() {
                            @Override
                            public Object invoke(Object proxy, Method method, Object[] args)
                                    throws Throwable {
                                Object result = null;
                                try {
                                    // 1.开启事务
                                    transactionManager.beginTransaction();
                                    // 2.业务操作
                                    result = method.invoke(accountService, args);
                                    // 3.提交事务 transactionManager.commit(); 
                                } catch (Exception e) {
                                    e.printStackTrace();
                                    // 4.回滚事务 
                                    transactionManager.rollback();
                                }
                            }
                        }
            }
        }

    CGLIB动态代理方式

    @Component
        public class CglibProxyFactory {
            @Autowired
            private AccountService accountService;
    
            @Autowired
            private TransactionManager transactionManager;
    
            public AccountService createAccountServiceCglibProxy() {
                AccountService accountServiceProxy = null;
                /**
                 * 参数一:目标对象的字节码对象
                 * 参数二:动作类,实现增强功能
                 */
                accountServiceProxy = (AccountService)
                        Enhancer.create(accountService.getClass(), new MethodInterceptor() {
                            @Override
                            public Object intercept(Object o, Method method, Object[] objects,
                                                    MethodProxy methodProxy) throws Throwable {
                                Object result = null;
                                try {
                                    // 1.开启事务
                                    transactionManager.beginTransaction();
                                    // 2.业务操作
                                    result = method.invoke(accountService, objects);
                                    // 3.提交事务
                                    transactionManager.commit();
                                } catch (Exception e) {
                                    e.printStackTrace();
                                    // 4.回滚事务
                                    transactionManager.rollback();
                                } finally {
                                    // 5.释放资源
                                    transactionManager.release();
                                }
                                return result;
                            }
                        });
                return accountServiceProxy;
            }
        }

     什么是AOP

    AOP 为 Aspect Oriented Programming 的缩写,意思为面向切面编程。

     AOP 是 OOP(面向对象编程) 的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

    这样做的好处是:

    1. 在程序运行期间,在不修改源码的情况下对方法进行功能增强
    2. 逻辑清晰,开发核心业务的时候,不必关注增强业务的代码
    3. 减少重复代码,提高开发效率,便于后期维护

    AOP底层实现

    实际上,AOP 的底层是通过 Spring 提供的的动态代理技术实现的。在运行期间,Spring通过动态代理技术动态的生成代理对象,代理对象方法执行时进行增强功能的介入,再去调用目标对象的方法,从而完成功能的增强。

    * Target(目标对象):代理的目标对象
    * Proxy (代理):一个类被 AOP 织入增强后,就产生一个结果代理类
    * Joinpoint(连接点):所谓连接点是指那些可以被拦截到的点。在spring中,这些点指的是方法,因为spring只支持方法类型的连接点
    * Pointcut(切入点):所谓切入点是指我们要对哪些 Joinpoint 进行拦截的定义
    * Advice(通知/ 增强):所谓通知是指拦截到 Joinpoint 之后所要做的事情就是通知
      分类:前置通知、后置通知、异常通知、最终通知、环绕通知
    * Aspect(切面):是切入点和通知(引介)的结合
    * Weaving(织入):是指把增强应用到目标对象来创建新的代理对象的过程。spring采用动态代理织
    入,而AspectJ采用编译期织入和类装载期织入

    AOP开发明确事项

    开发阶段(我们做的)

    1. 编写核心业务代码(目标类的目标方法) 切入点
    2. 把公用代码抽取出来,制作成通知(增强功能方法) 通知
    3. 在配置文件中,声明切入点与通知间的关系,即切面

    运行阶段(Spring框架完成的)

    Spring 框架监控切入点方法的执行。一旦监控到切入点方法被运行,使用代理机制,动态创建目标对象的代理对象,根据通知类别,在代理对象的对应位置,将通知对应的功能织入,完成完整的代码逻辑运行。

    底层代理实现

    在 Spring 中,框架会根据目标类是否实现了接口来决定采用哪种动态代理的方式。
    当bean实现接口时,会用JDK代理模式
    当bean没有实现接口,用cglib实现( 可以强制使用cglib(在spring配置中加入<aop:aspectj-autoproxy proxyt-target-class=”true”/>)

    基于XML的AOP开发

    XML配置AOP详解

    切点表达式

    execution([修饰符] 返回值类型 包名.类名.方法名(参数))

    • 访问修饰符可以省略
    • 返回值类型、包名、类名、方法名可以使用星号 * 代替,代表任意
    • 包名与类名之间一个点 . 代表当前包下的类,两个点 .. 表示当前包及其子包下的类
    • 参数列表可以使用两个点 .. 表示任意个数,任意类型的参数列表

    切点表达式抽取

    当多个增强的切点表达式相同时,可以将切点表达式进行抽取,在增强中使用 pointcut-ref 属性代替pointcut 属性来引用抽取后的切点表达式。

    <aop:config>
      <!--抽取的切点表达式-->
    <aop:pointcut id="myPointcut" expression="execution(* com.lagou.service..*.*
    (..))"> </aop:pointcut>
      <aop:aspect ref="myAdvice">
        <aop:before method="before" pointcut-ref="myPointcut"></aop:before>
      </aop:aspect>
    </aop:config>

    通知类型

    通知的配置语法:

    <aop:通知类型 method=“通知类中方法名” pointcut=“切点表达式"></aop:通知类型>

      注意:通常情况下,环绕通知都是独立使用的

    基于注解的AOP开发

    通知类型

    通知的配置语法:@通知注解(“切点表达式")

     当前四个通知组合在一起时,执行顺序如下:

    @Before -> @After -> @AfterReturning(如果有异常:@AfterThrowing)

    纯注解配置

    @Configuration
    @ComponentScan("com.lagou")
    @EnableAspectJAutoProxy //替代 <aop:aspectj-autoproxy />
    public class SpringConfig {
     
    }

    小结

    * 使用@Aspect注解,标注切面类
    * 使用@Before等注解,标注通知方法
    * 使用@Pointcut注解,抽取切点表达式
    * 配置aop自动代理 <aop:aspectj-autoproxy/> 或 @EnableAspectJAutoProxy

    利用aop注解和环绕通知案例

    public class TransactionManager {
      @Autowired
      ConnectionUtils connectionUtils;
      @Around("execution(* com.lagou.serivce..*.*(..))")
      public Object around(ProceedingJoinPoint pjp) {
        Object object = null;
        try {
          // 开启事务
          connectionUtils.getThreadConnection().setAutoCommit(false);
          // 业务逻辑
          pjp.proceed();
          // 提交事务
          connectionUtils.getThreadConnection().commit();
       } catch (Throwable throwable) {
          throwable.printStackTrace();
          // 回滚事务
          try {
            connectionUtils.getThreadConnection().rollback();
         } catch (SQLException e) {
            e.printStackTrace();
         }
       } finally {
          try {
            connectionUtils.getThreadConnection().setAutoCommit(true);
            connectionUtils.getThreadConnection().close();
            connectionUtils.removeThreadConnection();
         } catch (SQLException e) {
            e.printStackTrace();
         }
       }
        return object;
     }
    }

    Spring的JdbcTemplate

    JdbcTemplate是什么?

    JdbcTemplate是spring框架中提供的一个模板对象,是对原始繁琐的Jdbc API对象的简单封装。

    Spring的事务

    Spring中的事务控制方式

    Spring的事务控制可以分为编程式事务控制和声明式事务控制。

    编程式

    开发者直接把事务的代码和业务代码耦合到一起,在实际开发中不用。

    声明式

    开发者采用配置的方式来实现的事务控制,业务代码与事务代码实现解耦合,使用的AOP思想。

    编程式事务控制相关对象【了解】

    PlatformTransactionManager

    PlatformTransactionManager接口,是spring的事务管理器,里面提供了我们常用的操作事务的方法。

     注意:

    * PlatformTransactionManager 是接口类型,不同的 Dao 层技术则有不同的实现类。
    * Dao层技术是jdbcTemplate或mybatis时:
      DataSourceTransactionManager
    * Dao层技术是hibernate时:
      HibernateTransactionManager
    * Dao层技术是JPA时:
      JpaTransactionManager

    TransactionDefinition

    TransactionDefinition接口提供事务的定义信息(事务隔离级别、事务传播行为等等)

    1)事务隔离级别

    设置隔离级别,可以解决事务并发产生的问题,如脏读、不可重复读和虚读(幻读)。

    * ISOLATION_DEFAULT 使用数据库默认级别
    * ISOLATION_READ_UNCOMMITTED 读未提交
    * ISOLATION_READ_COMMITTED 读已提交
    * ISOLATION_REPEATABLE_READ 可重复读
    * ISOLATION_SERIALIZABLE 串行化

    2)事务传播行为

    事务传播行为指的就是当一个业务方法【被】另一个业务方法调用时,应该如何进行事务控制。

     * read-only(是否只读):建议查询时设置为只读

    * timeout(超时时间):默认值是-1,没有超时限制。如果有,以秒为单位进行设置

    TransactionStatus

    TransactionStatus 接口提供的是事务具体的运行状态。

     可以简单的理解三者的关系:事务管理器通过读取事务定义参数进行事务管理,然后会产生一系列的事务状态

    Spring中的事务控制主要就是通过这三个API实现的

    * PlatformTransactionManager 负责事务的管理,它是个接口,其子类负责具体工作
    * TransactionDefinition 定义了事务的一些相关参数
    * TransactionStatus 代表事务运行的一个实时状态

    基于XML的声明式事务控制【重点】

    在 Spring 配置文件中声明式的处理事务来代替代码式的处理事务。底层采用AOP思想来实现的。

    声明式事务控制明确事项:

    核心业务代码(目标对象) (切入点是谁?)
    事务增强代码(Spring已提供事务管理器))(通知是谁?)
    切面配置(切面如何配置?)

    事务参数的配置详解

    <tx:method name="transfer" isolation="REPEATABLE_READ" propagation="REQUIRED"
    timeout="-1" read-only="false"/>
    * name:切点方法名称
    * isolation:事务的隔离级别
    * propogation:事务的传播行为
    * timeout:超时时间
    * read-only:是否只读

    CRUD常用配置

    <tx:attributes>
      <tx:method name="save*" propagation="REQUIRED"/>
      <tx:method name="delete*" propagation="REQUIRED"/>
      <tx:method name="update*" propagation="REQUIRED"/>
      <tx:method name="find*" read-only="true"/>
      <tx:method name="*"/>
    </tx:attributes>

    基于注解的声明式事务控制【重点】

    常用注解

    1)修改service层,增加事务注解

    @Service
    public class AccountServiceImpl implements AccountService {
          @Autowired
          private AccountDao accountDao;
        @Transactional(propagation = Propagation.REQUIRED, isolation =
        Isolation.REPEATABLE_READ, timeout = -1, readOnly = false)
          @Override
          public void transfer(String outUser, String inUser, Double money) {
            accountDao.out(outUser, money);
            int i = 1 / 0;
            accountDao.in(inUser, money);
         }
    }

    2)修改spring核心配置文件,开启事务注解支持

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w2.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
    http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/aop
    http://www.springframework.org/schema/aop/spring-aop.xsd
       http://www.springframework.org/schema/tx
    http://www.springframework.org/schema/tx/spring-tx.xsd">
      <!--省略之前datsSource、jdbcTemplate、组件扫描配置-->
     
      <!--事务管理器-->
      <bean id="transactionManager"
    class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
      </bean>
     
      <!--事务的注解支持-->
      <tx:annotation-driven/>
    </beans>

    纯注解

    核心配置类

    @Configuration  // 声明为spring配置类
    @ComponentScan("com.lagou") // 扫描包
    @Import(DataSourceConfig.class) // 导入其他配置类
    @EnableTransactionManagement // 事务的注解驱动
    public class SpringConfig {
      @Bean
      public JdbcTemplate getJdbcTemplate(@Autowired DataSource dataSource) {
        return new JdbcTemplate(dataSource);
      }
      @Bean("transactionManager")
      public PlatformTransactionManager getPlatformTransactionManager(@Autowired
        DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
      }
    }

    数据源配置类

    @PropertySource("classpath:jdbc.properties")
    public class DataSourceConfig {
      @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
      public DataSource getDataSource() {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName(driver);
        dataSource.setUrl(url);
        dataSource.setUsername(username);
        dataSource.setPassword(password);
        return dataSource;
     }
    }

    Spring集成web环境

    ApplicationContext应用上下文获取方式

    应用上下文对象是通过  new ClasspathXmlApplicationContext(spring配置文件) 方式获取的,但是每次从容器中获得Bean时都要编写  new ClasspathXmlApplicationContext(spring配置文件) ,这样的弊端是配置文件加载多次,应用上下文对象创建多次。

    解决思路分析:

    在Web项目中,可以使用ServletContextListener监听Web应用的启动,我们可以在Web应用启动时,就加载Spring的配置文件,创建应用上下文对象ApplicationContext,在将其存储到最大的域servletContext域中,这样就可以在任意位置从域中获得应用上下文ApplicationContext对象了。

    Spring提供获取应用上下文的工具

    上面的分析不用手动实现,Spring提供了一个监听器ContextLoaderListener就是对上述功能的封
    装,该监听器内部加载Spring配置文件,创建应用上下文对象,并存储到ServletContext域中,提供
    了一个客户端工具WebApplicationContextUtils供使用者获得应用上下文对象。

    所以我们需要做的只有两件事:

    1. 在web.xml中配置ContextLoaderListener监听器(导入spring-web坐标)
    2. 使用WebApplicationContextUtils获得应用上下文对象ApplicationContext

    实现

    1)导入Spring集成web的坐标

    <dependency>
      <dependency>
       <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.1.5.RELEASE</version>
      </dependency>
       <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-web</artifactId>
      <version>5.1.5.RELEASE</version>
    </dependency>

    2)配置ContextLoaderListener监听器

    <!--全局参数-->
    <context-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:applicationContext.xml</param-value></context-param>
    <!--Spring的监听器-->
    <listener>
      <listener-class>
       org.springframework.web.context.ContextLoaderListener
    </listener-class>
    </listener>

    3)通过工具获得应用上下文对象

    ApplicationContext applicationContext =  
      WebApplicationContextUtils.getWebApplicationContext(servletContext);
    Object obj = applicationContext.getBean("id");
  • 相关阅读:
    在浏览器应用中使用 gRPC
    gRPC 客户端工厂集成
    gRPCurl 测试 gRPC 服务
    links
    Flex布局
    使用 IHttpClientFactory 实现复原 HTTP 请求
    Dex Common
    Dex MVVM
    日志
    配置
  • 原文地址:https://www.cnblogs.com/zhf123/p/14432847.html
Copyright © 2011-2022 走看看