Spring框架 之IOC容器 和AOP详解

主要分析点:

一、Spring开源框架的简介 

二、Spring下IOC容器和DI(依赖注入Dependency injection)

三、Spring下面向切面编程(AOP)和事务管理配置 

一、Spring开源框架的简介 

  Spring是一个开源框架,Spring是于2003 年兴起的一个轻量级的Java 开发框架,由Rod Johnson 在其著作Expert One-On-One J2EE Development and Design中阐述的部分理念和原型衍生而来。它是为了解决企业应用开发的复杂性而创建的。Spring使用基本的JavaBean来完成以前只可能由EJB完成的事情。然而,Spring的用途不仅限于服务器端的开发。从简单性、可测试性和松耦合的角度而言,任何Java应用都可以从Spring中受益。 简单来说,Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架。

  spring的基本框架主要包含六大模块:DAO、ORM、AOP、JEE、WEB、CORE

Spring DAO:Spring提供了对JDBC的操作支持:JdbcTemplate模板工具类 。

Spring ORM:Spring可以与ORM框架整合。例如Spring整合Hibernate框架,其中Spring还提供HibernateDaoSupport工具类,简化了Hibernate的操作 。

Spring WEB:Spring提供了对Struts、Springmvc的支持,支持WEB开发。与此同时Spring自身也提供了基于MVC的解决方案 。

Spring  AOP:Spring提供面向切面的编程,可以给某一层提供事务管理,例如在Service层添加事物控制 。

Spring   JEE:J2EE开发规范的支持,例如EJB 。

Spring Core:提供IOC容器对象的创建和处理依赖对象关系 。

二、Spring下IOC容器和DI(依赖注入Dependency injection)

  IOC容器:就是具有依赖注入功能的容器,是可以创建对象的容器,IOC容器负责实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。通常new一个实例,控制权由程序员控制,而"控制反转"是指new实例工作不由程序员来做而是交给Spring容器来做。。在Spring中BeanFactory是IOC容器的实际代表者。

  DI(依赖注入Dependency injection) :在容器创建对象后,处理对象的依赖关系。

  依赖注入spring的注入方式:

      • set注入方式
      • 静态工厂注入方式
      • 构造方法注入方式
      • 基于注解的方式

1、set注入方式:

控制层代码:

private OrderServiceImp orderService;

public void setOrderService(OrderServiceImp orderService) {
       this.orderService = orderService;
}

Spring配置XML文件:其中配置声明OrderAction类存在属性orderService。程式运行时候,会将已经实例化的orderService对象调用setOrderService方式注入。

<bean name="orderAction" class="com.pec.action.OrderAction">
        <property name="orderService" ref="orderService"></property>
</bean>
<bean name="orderService" class="com.pec.service.imp.OrderServiceImp"></bean>

2、构造器注入方式:

控制层代码:

private OrderServiceImp orderService;

public OrderAction(OrderServiceImp orderService) {
        this.orderService = orderService;
    }

Spring配置XML文件:

<bean name="orderAction" class="com.pec.action.OrderAction">
      <constructor-arg ref="orderService"></constructor-arg>
</bean>
<bean name="orderService" class="com.pec.service.imp.OrderServiceImp"></bean>

3、基于注解的方式(推荐使用,比较便捷少配置)

控制层代码:

@Autowired   //@Resource
private OrderServiceImp orderService;

服务层代码:

@Service("orderService")
public class OrderServiceImp implements IOrderService {

    @Autowired
    private JavaOrderMDaoImp javaOrderMDao;

    @Autowired
    private JavaOrderDDaoImp javaOrderDDao;

    @Override
    public List<JavaOrderMList> findOrderM(OrderSearch search) {
        return javaOrderMDao.findJavaOrderM(search);
    }

    @Override
    public List<JavaOrderDList> findOrderD(OrderSearch search) {
        return javaOrderDDao.findJavaOrderD(search);
    }

}

DAO层代码:

@Repository("javaOrderMDao")
public class JavaOrderMDaoImp extends BaseHibernateDAO<JavaOrderM, Serializable> implements IJavaOrderMDao {...}
@Repository("javaOrderDDao")
public class JavaOrderDDaoImp extendsBaseHibernateDAO<JavaOrderD, Serializable> implements IJavaOrderDDao {...}

 注意点:

  ⑴ 持久层DAO层注解Repository中规定了名称,在Service层中声明名称必须一致。

  ⑵ 服务层Service层注解Service中规定了名称,在控制层中声明的名称必须一致。

  ⑶ 注解方式注入依赖注解:

@Component         把对象加入ioc容器,对象引用名称是类名,第一个字母小写
@Component(“name”) 把指定名称的对象,加入ioc容器
@Repository        主要用于标识加入容器的对象是一个持久层的组件(类)
@Service           主要用于标识加入容器的对象是一个业务逻辑层的组件
@Controller        主要用于标识加入容器的对象是一个控制层的组件
@Resource          注入属性(DI), 会从容器中找对象注入到@Resource修饰的对象上
@Autowired         注入属性(DI), 会从容器中找对象注入到@Autowired修饰的对象上

   ⑷ 注解可以简化配置,提升开发效率,但是也不利于后期维护。

注:@Autowired与@Resource的区别

三、Spring下面向切面编程(AOP)和事务管理配置 

  AOP就是纵向的编程,如业务1和业务2都需要一个共同的操作,与其往每个业务中都添加同样的代码,不如写一遍代码,让两个业务共同使用这段代码。在日常有订单管理、商品管理、资金管理、库存管理等业务,都会需要到类似日志记录事务控制、权限控制、性能统计、异常处理及事务处理等。AOP把所有共有代码全部抽取出来,放置到某个地方集中管理,然后在具体运行时,再由容器动态织入这些共有代码。

AOP涉及名称:

切面(Aspect):其实就是共有功能的实现。如日志切面、权限切面、事务切面等。在实际应用中通常是一个存放共有功能实现的普通Java类,之所以能被AOP容器识别成切面,是在配置中指定的。

通知(Advice):是切面的具体实现。以目标方法为参照点,根据放置的地方不同,可分为前置通知(Before)、后置通知(AfterReturning)、异常通知(AfterThrowing)、最终通知(After)与环绕通知(Around)5种。在实际应用中通常是切面类中的一个方法,具体属于哪类通知,同样是在配置中指定的。

连接点(Joinpoint):就是程序在运行过程中能够插入切面的地点。例如,方法调用、异常抛出或字段修改等,但Spring只支持方法级的连接点。

切入点(Pointcut):用于定义通知应该切入到哪些连接点上。不同的通知通常需要切入到不同的连接点上,这种精准的匹配是由切入点的正则表达式来定义的。

目标对象(Target):就是那些即将切入切面的对象,也就是那些被通知的对象。这些对象中已经只剩下干干净净的核心业务逻辑代码了,所有的共有功能代码等待AOP容器的切入。

代理对象(Proxy):将通知应用到目标对象之后被动态创建的对象。可以简单地理解为,代理对象的功能等于目标对象的核心业务逻辑功能加上共有功能。代理对象对于使用者而言是透明的,是程序运行过程中的产物。

织入(Weaving):将切面应用到目标对象从而创建一个新的代理对象的过程。这个过程可以发生在编译期、类装载期及运行期,当然不同的发生点有着不同的前提条件。譬如发生在编译期的话,就要求有一个支持这种AOP实现的特殊编译器;发生在类装载期,就要求有一个支持AOP实现的特殊类装载器;只有发生在运行期,则可直接通过Java语言的反射机制与动态代理机制来动态实现。

 

  Spring使用AOP配置事务管理由三个部分组成,分别是DataSourceTransactionManager代理机制这三部分,无论哪种配置方式,一般变化的只是代理机制这部分。DataSource、TransactionManager这两部分只是会根据数据访问方式有所变化,比如使用hibernate进行数据访问时,DataSource实际为SessionFactory,TransactionManager的实现为HibernateTransactionManager。

spring事务配置的五种方式:每个Bean都有一个代理、所有Bean共享一个代理基类、使用拦截器、使用tx标签配置的拦截器、全注解

1、使用tx标签配置的拦截器

<!--4、配置hibernate属性 -->
    <!--引入db.properties属性文件 -->
    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="location" value="classpath:db.properties"></property>
    </bean>
    <!-- 配置数据源,连接池使用c3p0,详细信息参见hibernate官方文档"基础配置章节" -->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
        destroy-method="close" dependency-check="none">
        <property name="driverClass">
            <value>${datasource.driverClassName}</value>
        </property>
        <property name="jdbcUrl">
            <value>${datasource.url}</value>
        </property>
        <property name="user">
            <value>${datasource.username}</value>
        </property>
        <property name="password">
            <value>${datasource.password}</value>
        </property>
        <property name="acquireIncrement">
            <!--当连接池中的连接耗尽的时候c3p0一次同时获取的连接数。Default: 3 -->
            <value>${c3p0.acquireIncrement}</value>
        </property>
        <property name="initialPoolSize">
            <!--初始化时获取的连接数,取值应在minPoolSize与maxPoolSize之间。Default: 3 -->
            <value>${c3p0.initialPoolSize}</value>
        </property>
        <property name="minPoolSize">
            <!--连接池中保留的最小连接数。 -->
            <value>${c3p0.minPoolSize}</value>
        </property>
        <property name="maxPoolSize">
            <!--连接池中保留的最大连接数。Default: 15 -->
            <value>${c3p0.maxPoolSize}</value>
        </property>
        <property name="maxIdleTime">
            <!--最大空闲时间,60秒内未使用则连接被丢弃。若为0则永不丢弃。Default: 0 -->
            <value>${c3p0.maxIdleTime}</value>
        </property>
        <property name="idleConnectionTestPeriod">
            <!--每60秒检查所有连接池中的空闲连接。Default: 0 -->
            <value>${c3p0.idleConnectionTestPeriod}</value>
        </property>
        <property name="maxStatements">
            <!-- JDBC的标准参数,用以控制数据源内加载的PreparedStatements数量。但由于预缓存的statements 属于单个connection而不是整个连接池。所以设置这个参数需要考虑到多方面的因素。
                如果maxStatements与maxStatementsPerConnection均为0,则缓存被关闭。Default: 0 -->
            <value>${c3p0.maxStatements}</value>
        </property>
        <property name="numHelperThreads">
            <!-- C3P0是异步操作的,缓慢的JDBC操作通过帮助进程完成。扩展这些操作可以有效的提升性能, 通过多线程实现多个操作同时被执行。Default:
                3 -->
            <value>${c3p0.numHelperThreads}</value>
        </property>
    </bean>

    <!--配置 sessionFactory -->
    <bean id="sessionFactory"
        class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
        <property name="dataSource" ref="dataSource">
        </property>
        <!-- hibernate的设置 -->
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">${hibernate.dialect}</prop>
                <prop key="hibernate.show_sql"> ${hibernate.show_sql} </prop>
                <prop key="hibernate.jdbc.fetch_size">${hibernate.jdbc.fetch_size}</prop>
                <prop key="hibernate.jdbc.batch_size">${hibernate.jdbc.batch_size}</prop>
                <prop key="hibernate.connection.release_mode">${hibernate.connection.release_mode}</prop>
                <prop key="hibernate.format_sql">${hibernate.format_sql}</prop>
                <prop key="hibernate.connection.SetBigStringTryClob">true</prop>
            </props>
        </property>
        <!-- anotation注解扫描实体类 -->
        <property name="packagesToScan">
            <list>
                <value>com.pec.model</value>
            </list>
        </property>
    </bean>

    <!--5、Spring 配置声明式事物 -->

    <!-- 配置事务 -->
    <bean id="transactionManager"
        class="org.springframework.orm.hibernate3.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory"></property>
    </bean>

    <!-- 配置事务范围 -->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <tx:method name="get*" read-only="false" propagation="NOT_SUPPORTED" />
            <tx:method name="find*" read-only="false" propagation="NOT_SUPPORTED" />
            <tx:method name="save*" propagation="REQUIRED" />
            <tx:method name="update*" propagation="REQUIRED" />
            <tx:method name="delete*" propagation="REQUIRED" />
            <tx:method name="create*" propagation="REQUIRED" />
            <tx:method name="anscy*" propagation="REQUIRED" />
        </tx:attributes>
    </tx:advice>

    <!-- 定义切面 -->
    <aop:config proxy-target-class="true">
        <aop:pointcut id="pointcut" expression="execution(* com.pec.service..*.*(..))"  />
        <aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut" />
    </aop:config>

有几点需要说明:

⑴ pointcut中的三个"*"中,第一个*代表返回值,第二*代表service下子包,第三个*代表方法名,“(..)”代表方法参数。

⑵ 此时配置的切点在Service层,方法命名需要按照以上advice通知点开头命名。

⑶ 按照规定命名方法,会受到Spring事务的管控,保持操作的一致性。例如向数据库插入100条数据,前面99条记录都正常执行直至第100条出现错误,则事务管控会回滚到执行前的初始状态。

2、使用Bean代理

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
      http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
      http://www.springframework.org/schema/context
      http://www.springframework.org/schema/context/spring-context.xsd
      http://www.springframework.org/schema/tx
      http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
      http://www.springframework.org/schema/aop
      http://www.springframework.org/schema/aop/spring-aop-2.5.xsd"
      default-autowire="default">

    <!-- <bean name="userManager" class="com.tgb.manager.UserManagerImpl"></bean>
    <bean name="userController" class="com.tgb.web.UserController">
        <property name="userManager" ref="userManager"></property>
    </bean> -->
    <context:component-scan base-package="com.tgb.dao" />
    <context:component-scan base-package="com.tgb.entity" />
    <context:component-scan base-package="com.tgb.manager" />
    <context:component-scan base-package="com.tgb.web" />

    <!-- 引入init.properties中属性 -->
    <bean id="placeholderConfig" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="locations">
        <list>
            <value>classpath:config/spring/jdbc.properties</value>
        </list>
        </property>
    </bean>

    <!-- 配置数据源,连接池使用c3p0,详细信息参见hibernate官方文档"基础配置章节" -->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" >
        <property name="driverClass" value="${datasource.driverClassName}"></property>
        <property name="jdbcUrl" value="${datasource.url}"></property>
        <property name="user" value="${datasource.username}"></property>
        <property name="password" value="${datasource.password}"></property>
    </bean>

    <!-- 配置SessionFactory -->
    <bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">
                    ${hibernate.dialect}
                </prop>
                <prop key="hibernate.show_sql">
                    ${hibernate.show_sql}
                </prop>
                <prop key="hibernate.jdbc.fetch_size">
                    ${hibernate.jdbc.fetch_size}
                </prop>
                <prop key="hibernate.jdbc.batch_size">
                    ${hibernate.jdbc.batch_size}
                </prop>
                <prop key="hibernate.connection.release_mode">
                    ${hibernate.connection.release_mode}
                </prop>
                <prop key="hibernate.format_sql">
                    ${hibernate.format_sql}
                </prop>
                <prop key="hibernate.connection.SetBigStringTryClob">true</prop>
            </props>
        </property>
        <!-- anotation注解扫描实体类  -->
        <property name="annotatedClasses">
            <list>
                <value>com.tgb.entity.User</value>
            </list>
        </property>
    </bean>

    <!-- 配置一个事务管理器 将事务与Hibernate关联-->
    <bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory"/>
    </bean>

    <!-- 配置事务范围,使用代理的方式 -->
    <bean id="transactionProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean" abstract="true">
        <!--   为事务代理bean注入事务管理器-->
        <property name="transactionManager" >
            <ref bean="transactionManager"/>
        </property> 
         <!--设置事务属性范围-->
        <property name="transactionAttributes">
            <props>
                <prop key="add*">PROPAGATION_REQUIRED,-Exception</prop>
                <prop key="get">PROPAGATION_REQUIRED,-Exception</prop>
                <prop key="update*">PROPAGATION_REQUIRED,-myException</prop>
                <prop key="del*">PROPAGATION_REQUIRED</prop>
                <prop key="*">PROPAGATION_REQUIRED</prop>
            </props>
        </property>
    </bean> 

    <bean id="userDao" class="com.tgb.dao.UserDaoImpl">
        <property name="sessionFactory" ref="sessionFactory"></property>
    </bean>

    <bean id="userManagerBase" class="com.tgb.manager.UserManagerImpl">
        <property name="userDao" ref="userDao"></property>
    </bean>

    <!-- 此处为代理 -->
    <bean name="userManager" parent="transactionProxy">
        <property name="target" ref="userManagerBase"></property>
    </bean>    

</beans>

原文地址:https://www.cnblogs.com/RaymondSun/p/10058092.html

时间: 2024-10-13 14:01:45

Spring框架 之IOC容器 和AOP详解的相关文章

Spring框架学习[IoC容器高级特性]

1.通过前面4篇文章对Spring IoC容器的源码分析,我们已经基本上了解了Spring IoC容器对Bean定义资源的定位.读入和解析过程,同时也清楚了当用户通过getBean方法向IoC容器获取被管理的Bean时,IoC容器对Bean进行的初始化和依赖注入过程,这些是Spring IoC容器的基本功能特性.Spring IoC容器还有一些高级特性,如使用lazy-init属性对Bean预初始化.FactoryBean产生或者修饰Bean对象的生成.IoC容器初始化Bean过程中使用Bean

Spring框架——关于IOC容器和注解的36个小实验

实验1:通过IOC容器创建对象,并为属性赋值★ <bean id="page" class="com.neuedu.Bean.Page"> <property name="fontSize" value="大写"></property> <property name="fontNum" value="12"></property>

Spring 使用介绍(六)—— AOP详解

一.切入点语法 1)通配符 AOP支持的通配符: *:匹配任何数量字符 ..:匹配任何数量字符的重复,在类型模式中匹配任何数量子包,在方法参数模式中匹配任何数量参数 +:匹配指定类型的子类型,仅能作为后缀放在类型模式后边 实例: java.lang.String 匹配String类型 java.*.String 匹配java包下的任何"一级子包"下的String类型,如匹配java.lang.String,但匹配java.String或java.lang.ss.String java.

Spring的AOP详解

Spring的AOP详解 一.AOP基础 1.1AOP是什么 考虑这样一个问题:需要对系统中的某些业务做日志记录,比如支付系统中的支付业务需要记录支付相关日志,对于支付系统可能相当复杂,比如可能有自己的支付系统,也可能引入第三方支付平台,面对这样的支付系统该如何解决呢? 传统解决方案 1.日志部分定义公共类LogUtils,定义logPayBegin方法用于记录支付开始日志, logPayEnd用于记录支付结果 logPayBegin(long userId,long money) logPay

spring框架学习(六)AOP

spring框架学习(六)AOP AOP(Aspect-OrientedProgramming)面向方面编程,与OOP完全不同,使用AOP编程系统被分为方面或关注点,而不是OOP中的对象. AOP的引入 在OOP面向对象的使用中,无可避免的会出现代码重复,而且使用面向对象的编程方式,这种重复无法避免,比如用户权限判断中,根据相应的权限执行相应的方法:在servlet中设置编码格式时,同样相同的代码出现很多次,而且还根业务无关,很容易忘记写,结果运行的时候就出现乱码拉.这种重复代码不仅使编码麻烦,

Spring技术内幕——Spring Framework的IOC容器实现(一)

一.SpringIOC容器概述 IOC容器和依赖反转的模式 在面向对象的系统中,对象封装了数据和对数据的处理,对象的依赖关系常常体现在对数据和方法的依赖上.这些依赖关系可以通过把对象的依赖注入交给框架IOC容器来完成.他可以再解耦代码的同时提高了代码的可测试性. 依赖控制反转的实现由很多种方式,在Spring中,IOC容器是实现这个模式的载体,他可以再对象生成或者初始化时直接将数据注入到对象中,也可以通过将对象引用注入到对象数据域中的方式来注入对方法调用的依赖.这种依赖注入是可以递归的,对象被逐

Spring核心之Ioc容器走读笔记

其实说到Spring的核心,无非指的就是Ioc容器和AOP. Spring降低了应用的负载和框架的侵入性,依靠的解决方案正是Ioc和AOP的支持. 学习Spring的Ioc和Aop的设计模式可以帮助我们在自己编写代码的时候如何优雅的设计和实现. 这里就只记录一下自己对Ioc容器设计和实现的走读和思考. 在查看Spring Ioc容器的设计文档和源代码后,发现其实只有2类主要的容器: 一类是实现BeanFactory接口,这类的容器只实现了基本的方法,从名字上就大概能知道是什么功能:一类是实现Ap

好程序员Java干货分享Spring框架之IOC原理

好程序员Java干货分享Spring框架之IOC原理,前言:Spring框架是我们进行企业级开发的最常用框架,本章我们将了解Spring框架,并学习Spring的IOC特性以及IOC的实现原理:注解和反射. Spring框架简介 Spring是一种轻量级的控制反转(IOC)和面向切面编程(AOP)的容器框架,能够为企业级开发提供一站式服务. Spring的优点有 1.方便解耦,简化开发 通过Spring提供的IoC容器,我们可以将对象之间的依赖关系交由Spring进行控制,避免硬编码所造成的过度

Spring 总览及 IOC 容器的使用 —— Spring 官方文档解读(一)

Spring 总览及 IOC 容器的使用 -- Spring 官方文档解读(一) 什么是 Spring? spring 这个词在不同情况下有不同意义.可以指 Spring 框架本身,但更多地被用来表示 Spring 整个家族的产品. 设计理念 学习框架必须要知道它的设计理念,Spring 框架有着以下的理念: Spring 让你在架构种的各个层面有更多的选择,并且允许你尽晚的做出决策.比如,你在项目完成后可以通过更改配置来切换持久层的提供者. Spring 具有强大的灵活性,它不在意你是如何完成