1. 程式人生 > >spring框架IOC容器和AOC解析

spring框架IOC容器和AOC解析

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
</span><span style="color: #0000ff;">private</span><span style="color: #000000;"> JavaOrderMDaoImp <span style="color: #ff0000;"><strong>javaOrderMDao</strong></span>;

@Autowired
</span><span style="color: #0000ff;">private</span><span style="color: #000000;"> JavaOrderDDaoImp <strong><span style="color: #ff0000;">javaOrderDDao</span></strong>;

@Override
</span><span style="color: #0000ff;">public</span> List&lt;JavaOrderMList&gt;<span style="color: #000000;"> findOrderM(OrderSearch search) {
    </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> javaOrderMDao.findJavaOrderM(search);
}

@Override
</span><span style="color: #0000ff;">public</span> List&lt;JavaOrderDList&gt;<span style="color: #000000;"> findOrderD(OrderSearch search) {
    </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> 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>
&lt;!--配置 sessionFactory --&gt;
&lt;bean id="sessionFactory"
    <span style="color: #0000ff;">class</span>="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"&gt;
    &lt;property name="dataSource" ref="dataSource"&gt;
    &lt;/property&gt;
    &lt;!-- hibernate的設定 --&gt;
    &lt;property name="hibernateProperties"&gt;
        &lt;props&gt;
            &lt;prop key="hibernate.dialect"&gt;${hibernate.dialect}&lt;/prop&gt;
            &lt;prop key="hibernate.show_sql"&gt; ${hibernate.show_sql} &lt;/prop&gt;
            &lt;prop key="hibernate.jdbc.fetch_size"&gt;${hibernate.jdbc.fetch_size}&lt;/prop&gt;
            &lt;prop key="hibernate.jdbc.batch_size"&gt;${hibernate.jdbc.batch_size}&lt;/prop&gt;
            &lt;prop key="hibernate.connection.release_mode"&gt;${hibernate.connection.release_mode}&lt;/prop&gt;
            &lt;prop key="hibernate.format_sql"&gt;${hibernate.format_sql}&lt;/prop&gt;
            &lt;prop key="hibernate.connection.SetBigStringTryClob"&gt;<span style="color: #0000ff;">true</span>&lt;/prop&gt;
        &lt;/props&gt;
    &lt;/property&gt;
    &lt;!-- anotation註解掃描實體類 --&gt;
    &lt;property name="packagesToScan"&gt;
        &lt;list&gt;
            &lt;value&gt;com.pec.model&lt;/value&gt;
        &lt;/list&gt;
    &lt;/property&gt;
&lt;/bean&gt;

<span style="color: #ff0000;"><strong>&lt;!--5、Spring 配置宣告式事物 --&gt;</strong></span>

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

&lt;!-- 配置事務範圍 --&gt;
&lt;tx:advice id="txAdvice" transaction-manager="transactionManager"&gt;
    &lt;tx:attributes&gt;
        &lt;tx:method name="get*" read-only="false" propagation="NOT_SUPPORTED" /&gt;
        &lt;tx:method name="find*" read-only="false" propagation="NOT_SUPPORTED" /&gt;
        &lt;tx:method name="save*" propagation="REQUIRED" /&gt;
        &lt;tx:method name="update*" propagation="REQUIRED" /&gt;
        &lt;tx:method name="delete*" propagation="REQUIRED" /&gt;
        &lt;tx:method name="create*" propagation="REQUIRED" /&gt;
        &lt;tx:method name="anscy*" propagation="REQUIRED" /&gt;
    &lt;/tx:attributes&gt;
&lt;/tx:advice&gt;

&lt;!-- 定義切面 --&gt;
&lt;aop:config proxy-target-class="true"&gt;
    &lt;aop:pointcut id="pointcut" expression="execution(* com.pec.service..*.*(..))"  /&gt;
    &lt;aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut" /&gt;
&lt;/aop:config&gt;</span></strong></span></pre>
複製程式碼

 

 有幾點需要說明:

⑴ 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">
&lt;!-- &lt;bean name="userManager" <span style="color: #0000ff;">class</span>="com.tgb.manager.UserManagerImpl"&gt;&lt;/bean&gt;
&lt;bean name="userController" <span style="color: #0000ff;">class</span>="com.tgb.web.UserController"&gt;
    &lt;property name="userManager" ref="userManager"&gt;&lt;/property&gt;
&lt;/bean&gt; --&gt;
&lt;context:component-scan base-<span style="color: #0000ff;">package</span>="com.tgb.dao" /&gt;
&lt;context:component-scan base-<span style="color: #0000ff;">package</span>="com.tgb.entity" /&gt;
&lt;context:component-scan base-<span style="color: #0000ff;">package</span>="com.tgb.manager" /&gt;
&lt;context:component-scan base-<span style="color: #0000ff;">package</span>="com.tgb.web" /&gt;

&lt;!-- 引入init.properties中屬性 --&gt;
&lt;bean id="placeholderConfig" <span style="color: #0000ff;">class</span>="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"&gt;
    &lt;property name="locations"&gt;
    &lt;list&gt;
        &lt;value&gt;classpath:config/spring/jdbc.properties&lt;/value&gt;
    &lt;/list&gt;
    &lt;/property&gt;
&lt;/bean&gt;

&lt;!-- 配置資料來源,連線池使用c3p0,詳細資訊參見hibernate官方文件"基礎配置章節" --&gt;
&lt;bean id="dataSource" <span style="color: #0000ff;">class</span>="com.mchange.v2.c3p0.ComboPooledDataSource" &gt;
    &lt;property name="driverClass" value="${datasource.driverClassName}"&gt;&lt;/property&gt;
    &lt;property name="jdbcUrl" value="${datasource.url}"&gt;&lt;/property&gt;
    &lt;property name="user" value="${datasource.username}"&gt;&lt;/property&gt;
    &lt;property name="password" value="${datasource.password}"&gt;&lt;/property&gt;
&lt;/bean&gt;

&lt;!-- 配置SessionFactory --&gt;
&lt;bean id="sessionFactory" <span style="color: #0000ff;">class</span>="org.springframework.orm.hibernate4.LocalSessionFactoryBean"&gt;
    &lt;property name="dataSource" ref="dataSource" /&gt;
    &lt;property name="hibernateProperties"&gt;
        &lt;props&gt;
            &lt;prop key="hibernate.dialect"&gt;<span style="color: #000000;">
                ${hibernate.dialect}
            </span>&lt;/prop&gt;
            &lt;prop key="hibernate.show_sql"&gt;<span style="color: #000000;"> 
                ${hibernate.show_sql} 
            </span>&lt;/prop&gt;
            &lt;prop key="hibernate.jdbc.fetch_size"&gt;<span style="color: #000000;">
                ${hibernate.jdbc.fetch_size}
            </span>&lt;/prop&gt;
            &lt;prop key="hibernate.jdbc.batch_size"&gt;<span style="color: #000000;">
                ${hibernate.jdbc.batch_size}
            </span>&lt;/prop&gt;
            &lt;prop key="hibernate.connection.release_mode"&gt;<span style="color: #000000;">
                ${hibernate.connection.release_mode}
            </span>&lt;/prop&gt;
            &lt;prop key="hibernate.format_sql"&gt;<span style="color: #000000;">
                ${hibernate.format_sql}
            </span>&lt;/prop&gt;
            &lt;prop key="hibernate.connection.SetBigStringTryClob"&gt;<span style="color: #0000ff;">true</span>&lt;/prop&gt;
        &lt;/props&gt;
    &lt;/property&gt;
    &lt;!-- anotation註解掃描實體類  --&gt;
    &lt;property name="annotatedClasses"&gt;
        &lt;list&gt;
            &lt;value&gt;com.tgb.entity.User&lt;/value&gt;
        &lt;/list&gt;
    &lt;/property&gt;
&lt;/bean&gt;

&lt;!-- 配置一個事務管理器 將事務與Hibernate關聯--&gt;
&lt;bean id="transactionManager" <span style="color: #0000ff;">class</span>="org.springframework.orm.hibernate4.HibernateTransactionManager"&gt;
    &lt;property name="sessionFactory" ref="sessionFactory"/&gt;
&lt;/bean&gt;

&lt;!-- 配置事務範圍,使用代理的方式 --&gt;
&lt;bean id="transactionProxy" <span style="color: #0000ff;">class</span>="org.springframework.transaction.interceptor.TransactionProxyFactoryBean" <span style="color: #0000ff;">abstract</span>="true"&gt;  
  <span style="color: #ff0000;"><strong>  &lt;!--   為事務代理bean注入事務管理器--&gt; 
    &lt;property name="transactionManager" &gt;
        &lt;ref bean="transactionManager"/&gt;
    &lt;/property&gt; </strong> </span>
     &lt;!--設定事務屬性範圍--&gt;  
    &lt;property name="transactionAttributes"&gt;  
        &lt;props&gt;  
            &lt;prop key="add*"&gt;PROPAGATION_REQUIRED,-Exception&lt;/prop&gt;  
            &lt;prop key="get"&gt;PROPAGATION_REQUIRED,-Exception&lt;/prop&gt; 
            &lt;prop key="update*"&gt;PROPAGATION_REQUIRED,-myException&lt;/prop&gt;  
            &lt;prop key="del*"&gt;PROPAGATION_REQUIRED&lt;/prop&gt;  
            &lt;prop key="*"&gt;PROPAGATION_REQUIRED&lt;/prop&gt;      
        &lt;/props&gt;  
    &lt;/property&gt;  
&lt;/bean&gt; 

<span style="color: #ff0000;"><strong>&lt;bean id="userDao" class="com.tgb.dao.UserDaoImpl"&gt;
    &lt;property name="sessionFactory" ref="sessionFactory"&gt;&lt;/property&gt;
&lt;/bean&gt;

&lt;bean id="userManagerBase" class="com.tgb.manager.UserManagerImpl"&gt;
    &lt;property name="userDao" ref="userDao"&gt;&lt;/property&gt;
&lt;/bean&gt;

&lt;!-- 此處為代理 --&gt;
&lt;bean name="userManager" parent="transactionProxy"&gt;
    &lt;property name="target" ref="userManagerBase"&gt;&lt;/property&gt;
&lt;/bean&gt;   </strong> 
 </span></span>

</beans>

複製程式碼

 

參考連結:

http://www.cnblogs.com/andy6163/p/Andy.html  簡單理解——面向切面程式設計(AOP)

http://blog.csdn.net/moreevan/article/details/11977115  pring AOP 實現原理

http://blog.csdn.net/it_man/article/details/5074371  spring事務配置的五種方式

http://www.cnblogs.com/rushoooooo/archive/2011/08/28/2155960.html  Spring宣告式事務配置管理方法

 

標籤: IOC AOP 事務管理 事務配置 好文要頂 關注我 收藏該文 小猩
關注 - 4
粉絲 - 32 +加關注 9 0 « 上一篇: Hibernate 表對映 主鍵生成策略與複合主鍵
» 下一篇: JAVA 異常處理機制
	</div>
	<p class="postfoot">
		posted on <span id="post-date">2016-09-03 16:09</span> <a href="https://www.cnblogs.com/xiaoxing/">小猩</a> 閱讀(<span id="post_view_count">44024</span>) 評論(<span id="post_comment_count">5</span>)  <a href="https://i.cnblogs.com/EditPosts.aspx?postid=5836835" rel="nofollow">編輯</a> <a href="#" onclick="AddToWz(5836835);return false;">收藏</a>
	</p>
</div>