Spring

1.IOC与DI

  • inverse of control 控制反转

    我们创建对象的方式反转了。以前对象的创建由开发人员自己维护,包括依赖注入也是自己注入。使用spring之后,对象的创建及依赖关系可以由spring完成创建及依赖注入。

    控制反转反转的是对象的创建方式,由自己创建改为由程序创建

  • dependency injection依赖注入

    实现IOC思想需要di支持。

    注入方法:set方法注入,构造方法注入,字段注入

    注入类型:值类型注入(8大基本数据类型),引用类型注入

2.BeanFactory与ApplicationContext

  • BeanFactory

    spring原始接口,针对原始接口的实现类的功能比较单一

    BeanFactory接口实现类的容器,特点是每次在获得对象时才会创建对象

  • ApplicationContext

    每次容器启动时就会创建容器中配置的所有对象

    ClassPathXmlApplicationContext:从类路径下加载配置文件
    FileSystemXmlApplicationContext:从磁盘绝对路径下加载配置文件
    
  • 如果想让Spring容器随项目的创建而创建,随项目的关闭而销毁,需要在web.xml中监听Application创建销毁监听器(ServletContextListener)的实现类org.springframework.web.context.ContextLoaderListener并通过<context-param>来指定配置文件位置

    <context-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:applicationContext.xml</param-value>
    </context-param>
    

web开发中使用ApplicationContext,在资源匮乏的环境下可以使用BeanFactory

3.配置详解

  • Bean元素 ---- 描述需要Spring容器管理的对象

    • name

      给被管理对象起个名称,获得对象时,根据该名成获得对象,可以重复,可以使用特殊字符

    • class

      被管理对象的完整类名

    • scope

      • singleton:单例对象(默认值),标识为单例的对象在spring容器中只会被创建一次
      • prototype:多例原型,被标识为多例的对象,每次获得时才会创建,每次创建时都是新的对象,整合struts2时,ActionBean必须为多例-->
    • init-method

      配置一个方法为生命周期的初始方法,spring会在创建对象后立即调用

    • destroy-method

      配置一个方法为生命周期的销毁方法,spring容器在关闭并销毁所有容器中的对象之前调用

    <bean name="user" class="com.spring.learn1.entity.User" scope="singleton" init-method="init" destroy-method="destory"/>
    
  • 导入其他Spring配置文件

    <import resource="com/spring/learn1/applicationContext.xml"/>
    
  • Spring 创建对象的方式

    • 空参创建

      <bean name="user" class="com.spring.learn1.entity.User"/>
      
    • 静态工厂

      //调用UserFactory的createUser方法来创建对象,createUser为静态方法
      <bean name="user" class="com.spring.learn1.entity.UserFactory" factory-method="createUser"/>
      
    • 实例工厂

      //创建UserFactory对象,调用UserFactory的createUser方法来创建对象
      <bean name="user" factory-bean="userFactory" factory-method="createUser"/>
      <bean factory-bean="userFactory" class="com.spring.learn1.entity.UserFactory"/>
      
  • Spring属性注入方式

    • set方法注入

      //name:属性名称;  value:值;  ref:对象
      <bean name="user" class="com.spring.learn1.entity.User">
          <property name="name" value="tom"/>
          <property name="age" value="18"/>
          <property name="car" ref="car"/>
      </bean>
      <bean name="car" class="com.spring.learn1.entity.Car">
          <property name="carName" value="玛莎拉蒂"/>
      </bean>
      
    • 构造函数注入

      //constructor-arg:构造参数 name:参数名称 type:参数类型 index:注入位置 ref:对象 value:值
      <bean name="user" class="com.spring.learn1.entity.User">
          <constructor-arg name="name" type="java.lang.String" index="0" value="tom"/>
          <constructor-arg name="age" type="java.lang.Integer" index="1" value="20"/>
          <constructor-arg name="car" ref="car" index="2"/>
      </bean>
      
    • p名称空间注入

      xmlns:p="http://www.springframework.org/schema/p"
      
      <bean name="user" class="com.spring.learn1.entity.User" p:name="jack" p:age="16" p:car-ref="car"/>
      <bean name="car" class="com.spring.learn1.entity.Car">
          <property name="carName" value="玛莎拉蒂"/>
      </bean>
      
    • spel(Spring Expression Language,Spring 表达式语言)注入

      <bean name="user" class="com.spring.learn1.entity.User">
          <constructor-arg name="name" type="java.lang.String" index="0" value="tom"/>
          <constructor-arg name="age" type="java.lang.Integer" index="1" value="20"/>
          <constructor-arg name="gender" type="java.lang.String" index="2" value="男"/>
          <constructor-arg name="car" ref="car" index="3"/>
      </bean>
      <bean name="car" class="com.spring.learn1.entity.Car">
          <property name="carName" value="玛莎拉蒂"/>
      </bean>
      <bean name="user2" class="com.spring.learn1.entity.User">
          <property name="name" value="#{user.name}"/><!-- 引用user的name -->
          <property name="gender" value="#{'女'}"/><!-- 定义为女 -->
          <property name="age" value="#{user.getAge()}"/><!-- 通过调用方法设置age -->
          <property name="car" ref="car"/><!-- 引用对象采用此方式 -->
      </bean>
      
  • Spring复杂类型注入

    • 数组

    • list

    • map

    • properties

      <bean name="ot" class="com.spring.learn1.entity.OT">
          <!-- 如果数组中只准备注入一个值或者一个对象,直接使用value或ref即可 -->
          <!--<property name="sUsers" ref="user"/>-->
          <property name="sUsers">
              <array>
                  <value>"tom"</value>
                  <value>"jerry"</value>
                  <ref bean="user2"/>
              </array>
          </property>
      
          <!-- 如果list,set中只准备注入一个值或者一个对象,直接使用value或ref即可 -->
          <!--<property name="userList" ref="user"/>-->
          <property name="userList">
              <list>
                  <value>"tom"</value>
                  <value>"jerry"</value>
                  <ref bean="user2"/>
              </list>
          </property>
       <!-- Map注入 -->
          <property name="userMap">
              <map>
                  <entry key="name" value="tom"/>
                  <entry key="age" value="14"/>
                  <entry key="lover" value-ref="user2"/>
                  <entry key-ref="user2" value-ref="user"/>
              </map>
          </property>
      
          <property name="userProperties">
              <props>
                  <prop key="user" >root</prop>
                  <prop key="password">123</prop>
              </props>
          </property>
      </bean>
      

4.Spring生命周期管理

  • web.xml配置

    • 添加监听器org.springframework.web.context.ContextLoaderListener

    • 指定配置文件位置

      <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:applicationContext.xml</param-value>
      </context-param>
      
  • 获取

    WebApplicationContextUtils.getWebApplicationContext(ServletContext)

5.AOP

  • 底层实现原理(采用以下两种混合式开发,有接口优先采用动态代理)

    • 动态代理(实现InvocationHandler接口)

      被代理对象必须要实现接口才能产生代理对象

      public class UserFactory implements InvocationHandler {
          UserService userService;
      
          public UserFactory(UserService userService) {
              this.userService = userService; 
          }
      
          public UserService getUserServiceProxy(){
              return (UserService) Proxy.newProxyInstance(UserFactory.class.getClassLoader(),UserServiceImpl.class.getInterfaces(),this);
          }
      
          @Override
          public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
              System.out.println("开启事务");
              method.invoke(userService,args);
              System.out.println("关闭事务");
              return null;
          }
      
      }
      
    • cglib代理(第三方代理技术,实现MethodInterceptor接口)

      可以对任何类生成代理,原理是对目标对象进行继承代理,如果目标对象被final修饰,则该类无法对该对象代理

      public class MyCglbProxy implements MethodInterceptor {
          
          public UserServiceImpl getProxy() {
              Enhancer enhancer = new Enhancer();//帮我们生成代理对象
              enhancer.setSuperclass(UserServiceImpl.class);//设置代理的目标
              enhancer.setCallback(this);//代理的操作
              return (UserServiceImpl) enhancer.create();//创建代理对象
          }
      
          @Override
          public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
              System.out.println("开启事务");
              methodProxy.invokeSuper(object, args);
              System.out.println("关闭事务");
              return null;
          }
      }
      
  • AOP相关术语

    • Joinpoint(连接点):目标对象中可以进行增强的方法,即可以被拦截到的点。在 spring 中,这些点指的是方法,因为 spring 只支持方法类型的连接点.
    • Pointcut(切入点):目标对象中已经增强的方法,所谓切入点是指我们要对哪些 Joinpoint 进行拦截增强.
    • Advice(通知/增强):需要增强的代码,所谓通知是指拦截到 Joinpoint 之后所要做的事情就是通知.通知分为前置通知,后置通知,异常通知,最终通知,环绕通知(切面要完成的功能)
    • Introduction(引介):引介是一种特殊的通知在不修改类代码的前提下, Introduction 可以在运行期为类
      动态地添加一些方法或Field.
    • Target(目标对象):代理的目标对象
    • Weaving(织入):是指把Advice应用到Target来创建新的代理对象的过程.spring 采用动态代理织入,而 AspectJ 采用编译期织入和类装载期织入
    • Proxy(代理) :一个类被 AOP 织入增强后,就产生一个结果代理类
    • Aspect(切面): 是切入点和通知(引介)的结合
  • AOP开发步骤

    • 定义目标对象

    • 定义增强类

      public class MyAdvice {
          // 前置通知
          public void before() {
              System.out.println("这是前置通知");
          }
      
          // 后置通知(如果出现异常不会通知)
          public void after() {
              System.out.println("这是后置通知,如果出现异常不会调用");
          }
      
          // 异常通知
          public void afterException() {
              System.out.println("这是异常通知");
          }
      
          // 最终通知(无论是否出现异常,都会进行通知)
          public void end() {
              System.out.println("这是最终通知,无论是否出现异常,都会进行通知");
          }
      
          // 环绕通知(通知之前之后都会调用,切面要完成的功能)
          public Object around(ProceedingJoinPoint point) throws Throwable {
              System.out.println("这是环绕通知,之前的部分");
              Object proceed = point.proceed();//调用目标方法
              System.out.println("这是环绕通知,之后的部分");
              return proceed;
          }
      }
      
    • 将通知织入目标对象

      • 导入aop约束命名空间aop

      • 配置目标对象

        <!--配置目标对象-->
        <bean class="com.spring.learn3.entity.UserServiceImpl" name="target"/>
        
      • 配置通知对象

        <!--配置通知对象-->
        <bean class="com.spring.learn3.entity.MyAdvice" name="advice"/>
        
      • 将通知织入目标对象

        <!--织入-->
        <aop:config>
            <!--配置切入点-->
            <aop:pointcut id="user" expression="execution(*               com.spring.learn3.entity.*ServiceImpl.*(..))"
            <aop:aspect ref="advice">
              <!--前置通知(1)-->
                <aop:before method="before" pointcut-ref="user"/>
                <!--最终通知(2)-->
                <aop:after method="end" pointcut-ref="user"/>
                <!--环绕通知(3)-->
                <aop:around method="around" pointcut-ref="user"/>
                <!--后置通知(4)-->
                <aop:after-returning method="after" pointcut-ref="user"/>
                <!--异常通知(5)-->
                <aop:after-throwing method="afterException" pointcut-ref="user"/>
            </aop:aspect>
        </aop:config>
        //正常调用顺序1-3-4-3-2
        //异常调用顺序1-3-5-2
        

6)Spring整合JDBC----JdbcTemplate

  • JdbcTemplate使用方法

    //准备连接池
    ComboPooledDataSource dataSource = new ComboPooledDataSource();
    dataSource.setDriverClass("com.mysql.jdbc.Driver");
    dataSource.setJdbcUrl("jdbc:mysql://39.106.1.213:3306/hb?characterEncoding=utf-8");
    dataSource.setUser("root");
    dataSource.setPassword("123456");
    //建立JDBC模板对象
    JdbcTemplate template = new JdbcTemplate(dataSource);
    //执行sql语句
    String sql = "insert into User values(null,'肉丝')";
    template.update(sql);
    
  • Spring整合JDBC

    • Dao实现类中添加JdbcTemplate属性,实现set方法,依赖关系Dao---->JdbcTemplate---->DataSource

      <bean name="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
          <property name="driverClass" value="com.mysql.jdbc.Driver"/>
          <property name="jdbcUrl" value="jdbc:mysql://39.106.1.213:3306/hb?                                                      characterEncoding=utf-8"/>
          <property name="user" value="xxx"/>
          <property name="password" value="xxx"/>
      </bean>
      <bean name="template" class="org.springframework.jdbc.core.JdbcTemplate">
          <property name="dataSource" ref="dataSource"/>
      </bean>
      <bean name="userDao" class="com.dao.test1.entity.UserDaoImpl">
          <property name="template" ref="template"/>
      </bean>
      
    • Dao继承JdbcDaoSupport类,该类设置连接池时自动创建JdbcTemplate,依赖关系Dao---->DataSource

  • 读取外部Properties

    • 建立properties文件

      //src目录下db.properties
      jdbc.driverClass=com.mysql.jdbc.Driver
      jdbc.jdbcUrl=jdbc:mysql://39.106.1.213:3306/hb?characterEncoding=utf-8
      jdbc.user=root
      jdbc.password=123456
      
    • 配置

      <!--指定Spring读取db.properties-->
      <context:property-placeholder location="classpath:db.properties"/>
      
      <bean name="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
          <property name="driverClass" value="${jdbc.driverClass}"/>
          <property name="jdbcUrl" value="${jdbc.jdbcUrl}"/>
          <property name="user" value="${jdbc.user}"/>
          <property name="password" value="${jdbc.password}"/>
      </bean>
      

7)Spring事务

  • 平台事务管理器

    PlatformTransactionManager()
      ---- DataSourceTransactionManager(使用JDBC或iBatis进行持久化数据时使用)
      ---- HibernateTransactionManager(使用Hibernate进行持久化数据时使用)
    
  • 事务定义信息TransactionDefinition

    • 事务的隔离级别

    • 是否只读

    • 事务的传播行为(决定业务方法之间调用,事务应该如何处理)

      • 保证同一个事务中
        PROPAGATION_REQUIRED 支持当前事务,如果不存在,就新建一个(默认)
        PROPAGATION_SUPPORTS 支持当前事务,如果不存在,就不使用事务
        PROPAGATION_MANDATORY 支持当前事务,如果不存在,抛出异常

      • 保证没有在同一个事务中

        PROPAGATION_REQUIRES_NEW 如果有事务存在,挂起当前事务,创建一个新的事务
        PROPAGATION_NOT_SUPPORTED 以非事务方式运行,如果有事务存在,挂起当前事务
        PROPAGATION_NEVER 以非事务方式运行,如果有事务存在,抛出异常
        PROPAGATION_NESTED 如果当前事务存在,则嵌套事务执行

    • 超时信息

  • 事务的状态 TransactionStatus

  • Spring管理事务方式

    • 编码式 ---- 使用模板(TransactionTemplate)执行事务

      • 调用模板执行事务

        private TransactionTemplate transactionTemplate;
        
        transactionTemplate.execute(new TransactionCallbackWithoutResult() {
          @Override
          protected void doInTransactionWithoutResult(TransactionStatus transactionStatus)    {
                   //数据库业务
          }
        });
        
      • Spring中进行配置

        • 将核心事务管理器配置到spring

          <context:property-placeholder location="classpath:db.properties"/>
          
          <bean name="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
              <property name="driverClass" value="${jdbc.driverClass}"/>
              <property name="jdbcUrl" value="${jdbc.jdbcUrl}"/>
              <property name="user" value="${jdbc.user}"/>
              <property name="password" value="${jdbc.password}"/>
          </bean>
          
          <!-- 事务核心管理器,封装了所有事务操作,依赖连接池-->
          <bean name="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
              <property name="dataSource" ref="dataSource"/>
          </bean>
          
        • 配置TransactionTemplate模板

          <!--事务模板对象-->
          <bean name="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
              <property name="transactionManager" ref="transactionManager"/>
          </bean>
          
        • 配置操作事务的类,将事务模板注入

          <bean name="" class="">
              <property name="transactionTemplate" ref="transactionTemplate"/>
          </bean>
          
    • xml配置(AOP)

      • 导入约束

        beans: 最基本
        context:读取properties配置
        aop:配置aop
        tx:配置事务通知

      • 配置通知(以方法为参数进行配置)

        <context:property-placeholder location="classpath:db.properties"/>
        
        <bean name="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
            <property name="driverClass" value="${jdbc.driverClass}"/>
            <property name="jdbcUrl" value="${jdbc.jdbcUrl}"/>
            <property name="user" value="${jdbc.user}"/>
            <property name="password" value="${jdbc.password}"/>
        </bean>
        
        <!-- 事务核心管理器,封装了所有事务操作,依赖连接池-->
        <bean name="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <property name="dataSource" ref="dataSource"/>
        </bean>
        <!-- 配置事务通知 -->
        <tx:advice transaction-manager="transactionManager">
            <!--
            name:方法名称
            isolation="DEFAULT" 隔离级别
            propagation="REQUIRED" 传播行为
            read-only="false" 只读
            timeout="-1" 过期时间
            rollback-for="" -Exception
            no-rollback-for="" +Exception
            -->
            <tx:attributes>
                <tx:method name="save*" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false"/>
                <tx:method name="update*" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false"/>
                <tx:method name="delete*" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false"/>
                <tx:method name="get*" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="true"/>
        
                <tx:method name="persist*" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false"/>
                <tx:method name="modify*" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false"/>
                <tx:method name="remove*" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false"/>
                <tx:method name="find*" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="true"/>
            </tx:attributes>
        </tx:advice>
        
      • 织入

        <!-- 配置织入-->
        <aop:config>
          <!-- 配置切点表达式-->
            <aop:pointcut id="txPc" expression="execution(*                                       com.dao.test2.AccountServiceImpl.transfer())"/>
            <!-- 配置切面:通知+切点-->
            <!-- advice-ref:通知名称-->
            <!-- pointcut-ref:切点名称-->
            <aop:advisor advice-ref="txadvice" pointcut-ref="txPc"/>
        </aop:config>
        
    • 注解配置(AOP)

      • 导入约束

      • 配置xml

        <context:property-placeholder location="classpath:db.properties"/>
        
        <bean name="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
          <property name="driverClass" value="${jdbc.driverClass}"/>
          <property name="jdbcUrl" value="${jdbc.jdbcUrl}"/>
          <property name="user" value="${jdbc.user}"/>
          <property name="password" value="${jdbc.password}"/>
        </bean>
        
        <!-- 事务核心管理器,封装了所有事务操作,依赖连接池-->
        <bean name="transaction"                                                              class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
                <property name="dataSource" ref="dataSource"/>
        </bean>
        <tx:annotation-driven  transaction-manager="transaction"/>
        
      • 类或方法添加注解

        @Transactional(isolation = Isolation.REPEATABLE_READ,propagation = Propagation.REQUIRED,readOnly = false)
        

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容