程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> JAVA綜合教程 >> Spring 實踐之Java與設計模式 -拾遺

Spring 實踐之Java與設計模式 -拾遺

編輯:JAVA綜合教程

Spring 實踐之Java與設計模式 -拾遺


 

Spring 實踐

標簽: Java與設計模式


Junit集成

前面多次用到@RunWith@ContextConfiguration,在測試類添加這兩個注解,程序就會自動加載Spring配置並初始化Spring容器,方便Junit與Spring集成測試.使用這個功能需要在pom.xml中添加如下依賴:

pom.xml

    org.springframework
    spring-test
    4.2.0.RELEASE
@RunWith@ContextConfiguration加載Spring容器
/**
 * Spring 整合 Junit
 * Created by jifang on 15/12/9.
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:spring/applicationContext.xml")
public class BeanTest {

    @Autowired
    private Bean bean;

    @Test
    public void testConstruct() {
        Car car = bean.getCar();
        System.out.println(car);
    }
}

Web集成

我們可以利用ServletContext容器保存數據的唯一性, 以及ServletContextListener會在容器初始化時只被調用一次的特性. 在web.xml中配置spring-web包下的ContextLoaderListener來加載Spring配置文件/初始化Spring容器:

pom.xml/spring-web

    org.springframework
    spring-web
    4.2.0.RELEASE
配置監聽器(web.xml)

    org.springframework.web.context.ContextLoaderListener
加載Spring配置文件

    contextConfigLocation
    classpath:spring/applicationContext.xml

附: 完整web.xml文件git地址.

測試Servlet
@WebServlet(urlPatterns = "/servlet")
public class Servlet extends HttpServlet {

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doGet(request, response);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        ApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(this.getServletContext());
        Bean bean = context.getBean("bean", Bean.class);
        Car car = bean.getCar();
        System.out.println(car);
    }
}

在應用中,普通的JavaBean由Spring管理,可以使用@Autowired自動注入.但FilterServlet例外,他們都是由Servlet容器管理,因此其屬性不能用Spring注入,所以在實際項目中,一般都不會直接使用Servlet,而是用SpringMVC/WebX/Struts2之類的MVC框架以簡化開發,後面會有專門的博客介紹這類框架,在此就不做深入介紹了.

注: 運行Servlet不要忘記添加servlet-api依賴:

    javax.servlet
    javax.servlet-api
    3.1.0

文件加載

1. 引入properties

可以將需要經常修改的屬性參數值放到properties文件, 並在Spring文件中引入.

db.properties
## Data Source
mysql.driver.class=com.mysql.jdbc.Driver
mysql.url=jdbc:mysql://host:port/db?useUnicode=true&characterEncoding=UTF8
mysql.user=user
mysql.password=password

注意: value後不能有空格.

1.1 property-placeholde引入

在Spring配置文件中使用標簽引入properties文件,XML文件可通過${key}引用, Java可通過@Value("${key}")引用:

XML



    
    
    
    
Java
@Component
public class AccessLog {

    @Value("${mysql.url}")
    private String value;

    // ...
}

1.2 PropertiesFactoryBean引入

Spring提供了org.springframework.beans.factory.config.PropertiesFactoryBean,以加載properties文件, 方便在JavaBean中注入properties屬性值.

XML

    
        
            classpath*:common.properties
        
    
Java
@Controller
public class Bean {

    @Value("#{commonProperties['bean.properties.name']}")
    private String name;

    // ...
}

2. import其他Spring配置

如果Spring的配置項過多,可以按模塊將配置劃分多個配置文件(-datasource.xml/-dubbo-provider.xml/-bean.xml), 並由主配置applicationContext.xml文件引用他們,此時可用標簽引入:




事務管理

Spring事務管理高層抽象主要由PlatformTransactionManager/TransactionDefinition/TransactionStatus三個接口提供支持:


PlatformTransactionManager(事務管理器)

PlatformTransactionManager的主要功能是事務管理,Spring為不同的持久層框架提供了不同的PlatformTransactionManager實現:

事務 描述 DataSourceTransactionManager JDBCTemplate/MyBatis/iBatis持久化使用 HibernateTransactionManager Hibernate持久化使用 JpaTransactionManager JPA持久化使用 JdoTransactionManager JDO持久化使用 JtaTransactionManager JTA實現管理事務,一個事務跨越多個資源時使用

因此使用Spring管理事務,需要為不同持久層配置不同事務管理器實現.


TransactionDefinition(事務定義信息)

TransactionDefinition提供了對事務的相關配置, 如事務隔離級別/傳播行為/只讀/超時等:

隔離級別(isolation)
為解決事務並發引起的問題(髒讀/幻讀/不可重復讀),引入四個隔離級別: 隔離級別 描述 DEFAULT 使用數據庫默認的隔離級別 READ_UNCOMMITED 讀未提交 READ_COMMITTED 讀已提交(Oracle默認) REPEATABLE_READ 可重復讀(MySQL默認) SERIALIZABLE 串行化
傳播行為(propagation)
傳播行為不是數據庫的特性, 而是為了在業務層解決兩個事務相互調用的問題: 傳播類型 描述 REQUIRED 支持當前事務,如果不存在就新建一個(默認) SUPPORTS 支持當前事務,如果不存在就不使用事務 MANDATORY 支持當前事務,如果不存在則拋出異常 REQUIRES_NEW 如果有事務存在,則掛起當前事務新建一個 NOT_SUPPORTED 以非事務方式運行,如果有事務存在則掛起當前事務 NEVER 以非事務方式運行,如果有事務存在則拋出異常 NESTED 如果當前事務存在,則嵌套事務執行(只對DataSourceTransactionManager有效) 超時時間(timeout) 只讀(read-only)
只讀事務, 不能執行INSERT/UPDATE/DELETE操作.

TransactionStatus(事務狀態信息)

\

獲得事務執行過程中某一個時間點狀態.<喎?http://www.Bkjia.com/kf/ware/vc/" target="_blank" class="keylink">vcD4NCjwvYmxvY2txdW90ZT4NCjxociAvPg0KPGgzIGlkPQ=="聲明式事務管理">聲明式事務管理

Spring聲明式事務管理:無需要修改原來代碼,只需要為Spring添加配置(XML/Annotation),就可以為目標代碼添加事務管理功能.

需求: 轉賬案例(使用MyBatis).

AccountDAO




    
        UPDATE account
        SET money = money + #{0}
        WHERE name = #{1};
    

    
        UPDATE account
        SET money = money - #{0}
        WHERE name = #{1};
    
/**
 * @author jifang
 * @since 16/3/3 上午11:16.
 */
public interface AccountDAO {

    void transferIn(Double inMoney, String name);

    void transferOut(Double outMoney, String name);
}
Service
public interface AccountService {

    void transfer(String from, String to, Double money);
}
@Service("service")
public class AccountServiceImpl implements AccountService {

    @Autowired
    private AccountDAO dao;

    @Override
    public void transfer(String from, String to, Double money) {
        dao.transferOut(money, from);

        // 此處拋出異常, 沒有事務將導致數據不一致
        int a = 1 / 0;

        dao.transferIn(money, to);
    }
}
mybatis-configuration.xml/applicationContext-datasource.xml



    
    
        
    


    

    
    
        
        
        
        
        
        
        
        
        
            
                com.mysql.jdbc.jdbc2.optional.MysqlDataSource
                true
                250
                2048
            
        
    

    
        
    

    
    
        
        
    

    
    
        
        
    

applicationContext.xml(沒有事務)



    

    
Client
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:spring/applicationContext.xml")
public class SpringClient {

    @Autowired
    private AccountService service;

    @Test
    public void client() {
        service.transfer("from", "to", 10D);
    }
}

執行以上代碼, 將會導致數據前後不一致.


XML配置

Spring事務管理依賴AOP,而AOP需要定義切面(Advice+PointCut),在Spring內部提供了事務管理的默認Adviceorg.springframework.transaction.interceptor.TransactionInterceptor,並且Spring為了簡化事務配置,引入tx標簽:

引入tx的命名空間,配置Advice:

    



    
    
        
        
    
配置切面
Spring事務管理Advice基於SpringAOP,因此使用配置:

    

注解配置

使用注解配置事務, 可以省略切點的定義(因為注解放置位置就已經確定了PointCut的置), 只需配置Advice即可:

激活注解事務管理功能

    


在需要管理事務的業務類/業務方法上添加@Transactional注解
@Override
@Transactional(transactionManager = "transactionManger", readOnly = true)
public void transfer(String from, String to, Double money) {
    // ...
}

可以在注解@Transactional中配置與XML相同的事務屬性(isolation/propagation等).


實踐

更推薦使用XML方式來配置事務,實際開發時一般將事務集中配置管理. 另外, 事務的isolation/propagation一般默認的策略就已經足夠, 反而我們需要配置是否只讀(比如MySQL主從備份時,主庫一般提供讀寫操作,而從庫只提供讀操作), 因此其配置可以如下:



    



    
    
        
        
        
        
        
    




    
    
    
    
主從

    
    
        
    



    
    
        
        
        
        
        
    

   

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved