Netty網絡聊天室之使用spring管理各種組件

Spring是web開發的寵兒,不管mvc框架選擇structs還是SpringMVC,IOC容器都是選擇Spring。Spring有兩個主要的作用,一個是IOC(依賴注入),另一個是AOP(面向切面編程)。只要是java項目,就可以使用這個框架。
在這裏,我不過多對Spring進行佈道。說一下有沒有使用Spring的編碼習慣。若不採用Spring進行項目開發,我們每個類一般都是採用單例的模式,例如 UserService.getInstance();使用了Spring,就只需要在UserService加個註解就可以把它丟入spring容器(Spring默認創建對象就是使用單例模式)。如果其他模塊需要調用UserService的接口,只需要從spring容器把它拿出來即可,非常方便。

對於沒有接觸Spring的童鞋,只需要知道Spring是一個巨大的對象容器。使用@Component,@Servoce,@Controller,@Repository可以把對象放入容器,使用@Resource,@Autowired可以從容器裏取對象。

spring管理組件的配置方式

1. 項目裏受spring管理的組件是非常多的,所以我們需要能讓spring容器自動掃描所有組件,只需要在spring配置加上這一行就可以了

<context:component-scan base-package="com.kingston" />
2. 把組件交給spring容器管理,配置如下

@Repository
public interface UserDao 
3. 使用Spring容器裏的對象,配置如下

@Component
public class LoginService {

	@Autowired
	private UserDao userDao;
}

需要特別注意的是,這裏用Autowired註解從spring裏拿對象,LoginService本身也必須受spring管理,否則就需要手動從spring獲取bean。

緩存Spring容器本身引用

1. 不是所有對象都放在spring容器裏的。若某個對象本身沒有放入spring裏,想要拿spring容器的組件,就只能從spring的容器上下文環境中獲取。所以,有必要把這個spring容器上下文緩存起來。要獲取spring容器,只需要類實現ApplicationContextAware這個接口即可。像這樣

public class SpringContext implements ApplicationContextAware {
	/** spring容器上下文 */
	private static ApplicationContext applicationContext = null;
	/** 異步持久化服務 */
	private static AysncDbService aysncDbService;
	
	private static ChatService chatService;

	@Override
	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
		SpringContext.applicationContext = applicationContext;
	}
	
	public final static <T> T getBean(Class<T> clazz) {
		return applicationContext.getBean(clazz);
	}
	
	public final static <T> Collection<T> getBeansOfType(Class<T> clazz) {
		return applicationContext.getBeansOfType(clazz).values();
	}
	
	public final static <T> T getBean(String name, Class<T> requiredType) {
		return applicationContext.getBean(name, requiredType);
	}

	@Resource
	public void setAysncDbService(AysncDbService aysncDbService) {
		SpringContext.aysncDbService = aysncDbService;
	}
	
	public static AysncDbService getAysncDbService() {
		return aysncDbService;
	}
	
	@Resource
	public void setChatService(ChatService chatService) {
		SpringContext.chatService = chatService;
	}
	
	public final static ChatService getChatService() {
		return chatService;
	}
	
}
並把SpringContext配置成spring的組件

	<!-- 註冊spring上下文環境 -->
	<bean id="context" class="com.kingston.base.SpringContext" />
2. 非spring管理的實例想要獲取spring組件,就可以像這樣子了
	AbstractPacket  packet = (AbstractPacket)msg;
	System.err.println("receive pact, content is " + packet.getClass().getSimpleName());
	if(packet.getPacketType() == PacketType.ReqUserLogin ){
		ReqUserLoginPacket loginPact = (ReqUserLoginPacket)packet;
		
		LoginService loginMgr = SpringContext.getBean(LoginService.class);
		loginMgr.validateLogin(context,loginPact.getUserId(), loginPact.getUserPwd());
		return ;
	}

spring與mybatics的結合

使用了spring之後,數據庫連接的數據源,以及Mybatics的SqlSessionFactoryBean就統統在spring進行配置就可以了。

1. 使用mybatis-spring庫(mybatics整合spring的工具庫),可以直接讓spring掃描所有mybatics的mapper配置

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
		<property name="dataSource" ref="dataSource" />
		<property name="configLocation" value="config/mybatis-config.xml" />
		<!-- 自動掃描所有mapper配置 -->
		<property name="mapperLocations"
			value="classpath:com/kingston/data/mybatis/*Mapper.xml" />
	</bean>
2. 使用mybatis-spring庫,可以自動掃描所有dao並注入到spring容器
	<!-- 自動掃描所有dao並注入到spring容器 -->
	<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
		<property name="basePackage" value="com.kingston.data.dao" />
	</bean>

3. 這樣一來,mybatics本身的配置就變得可有可無啦。不過,一些組件的別名申明還是可以放到mybatics的配置裏

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
  PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
	<!--別名申明 -->
	<typeAliases>
		<typeAlias type="com.kingston.data.model.User" alias="user" />
	</typeAliases>
	
</configuration>
UserMapper.xml配置裏的 resultType="user" ,這裏的 "user"就指向上面的完整類路徑
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.kingston.data.dao.UserDao">
	<select id="findById" parameterType="java.lang.Long"
		resultType="user">
		select * from user where userId=#{userId}
	</select>
	<insert id="addUser" parameterType="user">
		insert into user(userId,userName,authentication) 
			values(#{userId},#{userName},#{authentication})
	</insert>
	<update id="updateUser" parameterType="user">
		update user
		set
		userName=#{userName}
		where userId=#{userId}
	</update>
	<delete id="delUser" parameterType="java.lang.Long">
		delete from user
		where
		userId=#{userId}
	</delete>
</mapper>

Spring結合Groovy腳本實現熱部署

Groovy是JVM上的一門腳本語言,當Spring遇上了Groovy,就會締造完美的效果。當部分spring組件需要在程序運行過程中實現代碼熱部署,只需要用Groovy的類加載器加載。具體的操作可以看下點擊打開鏈接 這篇文章。
在實際使用環境,我們把需要熱更新的代碼統一放到src/groovy目錄下。需要注意的是,ides開發環境跟jar包生產環境獲取groovy目錄的spring組件的方式是不同的。
在ide環境,只要將src/groovy目錄標記爲代碼根目錄,spring容器啓動的時候,就可以掃描到groovy目錄下被spring註解標記的組件。
在生產環境,我們使用maven作爲打包工具,但maven 默認只把src/main目錄下的java文件編譯到目標jar包,我們自定義的src/groovy目錄是不會打進包裏的。這樣更好,因爲我們本來就不希望我們的groovy目錄被編譯成class。
我們希望groovy的目錄與jar包分離,並且以源碼的形式存在。當需要更新groovy裏某個文件的代碼時,直接替換文件即可。GroovyFactory類在掃描的時候,只要把掃描的根目錄指向跟jar包同一目錄下的groovy,也可以拿到groovy的spring組件。


全部代碼已在github上託管

服務端代碼請移步 --> netty聊天室服務器

客戶端代碼請移步 --> netty聊天室客戶端





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章