當柳上原的風吹向天際的時候...

          真正的快樂來源于創造

            BlogJava :: 首頁 :: 聯系 :: 聚合  :: 管理
            368 Posts :: 1 Stories :: 201 Comments :: 0 Trackbacks

          權限子系統與文檔處理子系統交織的弊病

          如同一個成規模的公司一樣,對于一個成規模的應用來說,內中會存在著各種子系統以執行不同的功能,而且為了協調工作,它們往往是交織在一起,就像上一個版本中權限子系統與文檔處理子系統交織一樣。

          子系統交織是必要的,但子系統間過多過緊密的耦合并不合理。因為交織會增加軟件系統的熵值,使得系統隨著功能的增加和細化變得越來越復雜而難于控制,最后不得不推倒重來,給個人和公司帶來巨大的損失。這是軟件業普遍的問題,在國內公司和外包公司都不罕見。

          因此,在程序的編寫過程中,程序員必須有意識的減少子系統之間的交織,使它們離散化,利用Spring的AOP可以有效幫助我們做到這一點。對于簡單值權限系統,使用AOP進行子系統離散化的具體思路如下:

          1.將DocService中負責權限的代碼(屬性和函數)都分離,放置到一個專門的權限處理類PrivilegeService中。
          2.使用Spring的ProxyFactoryBean,做成DocService的代理,讓PrivilegeService作為它的前置處理器。
          3.在PrivilegeService的before方法中,執行權限檢查,如果權限值不夠則拋出異常。

          分離后DocService簡潔的代碼
          package com.heyang.aopstyle.service;

          import com.heyang.traditonal.domain.Doc;
          import com.heyang.traditonal.domain.User;
          import com.heyang.traditonal.service.IDocService;

          /**
           * 為領域對象Doc提供服務
           * 
           * 
          @author 何楊(heyang78@gmail.com)
           * 
           * 
          @since 2008-12-30 下午05:13:29
           * 
          @version 1.00
           
          */

          public class DocService implements IDocService {
              
          public void add(Doc doc, User user) {
                  System.out.println(
          "" + doc + "交由dao處理(存入數據庫)");
              }


              
          public void delete(Doc doc, User user) {
                  System.out.println(
          "" + doc + "交由dao處理(從數據庫刪除)");
              }


              
          public void update(Doc doc, User user) {
                  System.out.println(
          "" + doc + "交由dao處理(更新數據庫中對應的記錄)");
              }

          }

          新組建的PrivilegeService類
          package com.heyang.aopstyle.service;

          import java.lang.reflect.Method;

          import org.springframework.aop.MethodBeforeAdvice;

          import com.heyang.aopstyle.exception.PrivilegeNotEnoughException;
          import com.heyang.traditional2.dao.PrivilegeDao;
          import com.heyang.traditonal.domain.User;

          /**
           * 實現權限子系統
           * 
          @author: 何楊(heyang78@gmail.com)
           * @date: 2009-1-2-下午04:19:13
           
          */

          public class PrivilegeService implements MethodBeforeAdvice{
              
          private PrivilegeDao privilegeDao;
              
              
          // 添加doc需要的權限名
              private String addDocPrivilegeName;
              
              
          // 刪除doc需要的權限名
              private String deleteDocPrivilegeName;
              
              
          // 更新doc需要的權限名
              private String updateDocPrivilegeName;
              
              
          /**
               * 在IDocService的實際方法開始前進行前置處理--權限檢查
               
          */

              
          public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable {
                  
          // 取得方法名
                  String mothodName=arg0.getName();
                  
                  
          // 取得用戶權限
                  User user=(User)arg1[1];
                  
          int userPrivilegeValue=user.getPrivilegePoint();
                  
                  
          // 根據方法名判斷用戶是否達到了需要的權限,否則拋出異常
                  if("add".equals(mothodName)){
                      
          if(userPrivilegeValue<=getPrivilegeValueBy(addDocPrivilegeName)){
                          
          throw new PrivilegeNotEnoughException("用戶權限必須達到"+getPrivilegeValueBy(addDocPrivilegeName)+"才能執行添加操作");
                      }

                  }

                  
          else if("delete".equals(mothodName)){
                      
          if(userPrivilegeValue<=getPrivilegeValueBy(deleteDocPrivilegeName)){
                          
          throw new PrivilegeNotEnoughException("用戶權限必須達到"+getPrivilegeValueBy(deleteDocPrivilegeName)+"才能執行刪除操作");
                      }

                  }

                  
          else if("update".equals(mothodName)){
                      
          if(userPrivilegeValue<=getPrivilegeValueBy(updateDocPrivilegeName)){
                          
          throw new PrivilegeNotEnoughException("用戶權限必須達到"+getPrivilegeValueBy(updateDocPrivilegeName)+"才能執行更新操作");
                      }

                  }

              }

              
              
              
          private int getPrivilegeValueBy(String name){
                  
          return privilegeDao.getValueBy(name);
              }


              
          public PrivilegeDao getPrivilegeDao() {
                  
          return privilegeDao;
              }


              
          public void setPrivilegeDao(PrivilegeDao privilegeDao) {
                  
          this.privilegeDao = privilegeDao;
              }


              
          public String getAddDocPrivilegeName() {
                  
          return addDocPrivilegeName;
              }


              
          public void setAddDocPrivilegeName(String addDocPrivilegeName) {
                  
          this.addDocPrivilegeName = addDocPrivilegeName;
              }


              
          public String getDeleteDocPrivilegeName() {
                  
          return deleteDocPrivilegeName;
              }


              
          public void setDeleteDocPrivilegeName(String deleteDocPrivilegeName) {
                  
          this.deleteDocPrivilegeName = deleteDocPrivilegeName;
              }


              
          public String getUpdateDocPrivilegeName() {
                  
          return updateDocPrivilegeName;
              }


              
          public void setUpdateDocPrivilegeName(String updateDocPrivilegeName) {
                  
          this.updateDocPrivilegeName = updateDocPrivilegeName;
              }

          }

          起輔助作用的PrivilegeNotEnoughException類,因為不想改變接口(或不能改變接口)故把異常類型定位運行期異常:
          package com.heyang.aopstyle.exception;

          /**
           * 權限不足異常
           * 
          @author: 何楊(heyang78@gmail.com)
           * @date: 2009-1-2-下午04:02:50
           
          */

          public class PrivilegeNotEnoughException extends RuntimeException{
              
          private static final long serialVersionUID = -6594794529337011115L;

              
          public PrivilegeNotEnoughException(String msg){
                  
          super(msg);
              }

          }

          最終配置文件
          <?xml version="1.0" encoding="UTF-8"?>
          <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
          <beans>
            
          <!-- 數據源 -->
            
          <bean id="dataSource"
              class
          ="org.springframework.jdbc.datasource.DriverManagerDataSource">
              
          <property name="driverClassName"
                value
          ="org.gjt.mm.mysql.Driver">
              
          </property>
              
          <property name="url" value="jdbc:mysql://127.0.0.1/test">
              
          </property>
              
          <property name="username" value="root"></property>
              
          <property name="password" value="hy"></property>
            
          </bean>

            
          <!-- 用于訪問數據庫的jdbcTemplate -->
            
          <bean id="jdbcTemplate"
              class
          ="org.springframework.jdbc.core.JdbcTemplate">
              
          <property name="dataSource">
                
          <ref bean="dataSource" />
              
          </property>
            
          </bean>
            
            
          <!-- 用于訪問數據庫的PrivilegeTB表,按權限名取出權限值的數據庫訪問類 -->
            
          <bean id="privilegeDao"
              class
          ="com.heyang.traditional2.dao.PrivilegeDao">
              
          <property name="jdbcTemplate">
                
          <ref bean="jdbcTemplate" />
              
          </property>
            
          </bean>

            
          <!-- 用于文件處理的IDocService實現類DocService -->
            
          <bean id="docService" class="com.heyang.aopstyle.service.DocService"/>
            
            
          <!-- 在執行docService的實際方法前進行權限檢查 -->
            
          <bean id="privilegeService" class="com.heyang.aopstyle.service.PrivilegeService">
              
          <property name="privilegeDao">
                
          <ref bean="privilegeDao" />
              
          </property>
              
          <property name="addDocPrivilegeName" value="addDocPrivilege" />
              
          <property name="deleteDocPrivilegeName" value="deleteDocPrivilege" />
              
          <property name="updateDocPrivilegeName" value="updateDocPrivilege" />   
            
          </bean>
            
            
          <!-- docService的代理對象 -->
            
          <bean id="docServiceProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
              
          <property name="proxyInterfaces">
                
          <value>com.heyang.traditonal.service.IDocService</value>
              
          </property>
              
          <property name="interceptorNames">
                
          <list>
                  
          <value>privilegeService</value>
                
          </list>
              
          </property>
              
          <property name="target">
                
          <ref bean="docService"/>
              
          </property>
            
          </bean>
          </beans>

          業務處理模擬過程
          package com.heyang.aopstyle;

          import org.springframework.context.ApplicationContext;
          import org.springframework.context.support.ClassPathXmlApplicationContext;

          import com.heyang.aopstyle.exception.PrivilegeNotEnoughException;
          import com.heyang.traditonal.domain.Doc;
          import com.heyang.traditonal.domain.User;
          import com.heyang.traditonal.service.IDocService;


          public class Main{
              
          public static void main(String[] args){
                  ApplicationContext ctx 
          = new ClassPathXmlApplicationContext("aopCtx.xml");
                  
                  IDocService docService
          =(IDocService)ctx.getBean("docServiceProxy");
                  
                  Doc doc
          =new Doc("論美國次貸危機的產生及影響");
                  User user
          =new User("中科院經濟所研究員",50);
                  
                  
          // 用戶向系統添加文章
                  try{
                      docService.add(doc, user);
                  }

                  
          catch(PrivilegeNotEnoughException ex){
                      System.out.println(ex.getMessage());
                  }

                  
                  
          // 用戶向系統更新文章
                  try{
                      doc.setName(
          "論美國次貸危機的產生及影響和我國應該采取的應對措施");
                      docService.update(doc, user);
                  }

                  
          catch(PrivilegeNotEnoughException ex){
                      System.out.println(ex.getMessage());
                  }

                  
                  
          // 用戶從系統撒刪除文章
                  try{
                      docService.delete(doc, user);
                  }

                  
          catch(PrivilegeNotEnoughException ex){
                      System.out.println(ex.getMessage());
                  }

              }

          }


          輸出
          2009-01-02 16:26:53,406 DEBUG [main] (DriverManagerDataSource.java:289- Creating new JDBC Connection to [jdbc:mysql://127.0.0.1/test]
          2009-01-02 16:26:56,578 DEBUG [main] (DataSourceUtils.java:312- Returning JDBC Connection to DataSource
          將文件 名
          =論美國次貸危機的產生及影響交由dao處理(存入數據庫)
          2009-01-02 16:26:56,593 DEBUG [main] (JdbcTemplate.java:382- Executing SQL query [select value from PrivilegeTB where name='updateDocPrivilege' ]
          2009-01-02 16:26:56,593 DEBUG [main] (DataSourceUtils.java:112- Fetching JDBC Connection from DataSource
          2009-01-02 16:26:56,593 DEBUG [main] (DriverManagerDataSource.java:289- Creating new JDBC Connection to [jdbc:mysql://127.0.0.1/test]
          2009-01-02 16:26:56,640 DEBUG [main] (DataSourceUtils.java:312- Returning JDBC Connection to DataSource
          將文件 名
          =論美國次貸危機的產生及影響和我國應該采取的應對措施交由dao處理(更新數據庫中對應的記錄)
          2009-01-02 16:26:56,640 DEBUG [main] (JdbcTemplate.java:382- Executing SQL query [select value from PrivilegeTB where name='deleteDocPrivilege' ]
          2009-01-02 16:26:56,640 DEBUG [main] (DataSourceUtils.java:112- Fetching JDBC Connection from DataSource
          2009-01-02 16:26:56,640 DEBUG [main] (DriverManagerDataSource.java:289- Creating new JDBC Connection to [jdbc:mysql://127.0.0.1/test]
          2009-01-02 16:26:56,703 DEBUG [main] (DataSourceUtils.java:312- Returning JDBC Connection to DataSource
          2009-01-02 16:26:56,859 DEBUG [main] (JdbcTemplate.java:382- Executing SQL query [select value from PrivilegeTB where name='deleteDocPrivilege' ]
          2009-01-02 16:26:56,859 DEBUG [main] (DataSourceUtils.java:112- Fetching JDBC Connection from DataSource
          2009-01-02 16:26:56,859 DEBUG [main] (DriverManagerDataSource.java:289- Creating new JDBC Connection to [jdbc:mysql://127.0.0.1/test]
          2009-01-02 16:26:56,953 DEBUG [main] (DataSourceUtils.java:312- Returning JDBC Connection to DataSource
          用戶權限必須達到60才能執行刪除操作


          例程下載
          http://www.aygfsteel.com/Files/heyang/AOPPrivilegeSample20090102170039.rar

          需要自行載入的包為:
          commons-logging-1.0.4.jar,log4j-1.2.14.jar,spring.jar,mysql-connector-java-5.0.6-bin.jar
          posted on 2009-01-02 16:54 何楊 閱讀(780) 評論(0)  編輯  收藏

          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          主站蜘蛛池模板: 延长县| 稷山县| 佛山市| 双牌县| 安仁县| 科尔| 海南省| 孟村| 常州市| 冕宁县| 墨江| 南丰县| 庆云县| 蛟河市| 依兰县| 旺苍县| 汝南县| 新龙县| 合山市| 垦利县| 宜阳县| 招远市| 东乌珠穆沁旗| 洛浦县| 汕头市| 汪清县| 永清县| 马龙县| 昭觉县| 阿城市| 奇台县| 嫩江县| 山阳县| 铅山县| 西充县| 页游| 锡林郭勒盟| 洪湖市| 安泽县| 晋江市| 松潘县|