在這裏,我不過多對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聊天室客戶端