Netty网络聊天室之使用spring管理各种组件

来源:互联网 发布:在国外买淘宝的软件 编辑:程序博客网 时间:2024/06/06 02:21
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容器管理,配置如下

@Repositorypublic interface UserDao 
3. 使用Spring容器里的对象,配置如下

@Componentpublic class LoginService {@Autowiredprivate 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;@Overridepublic 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);}@Resourcepublic void setAysncDbService(AysncDbService aysncDbService) {SpringContext.aysncDbService = aysncDbService;}public static AysncDbService getAysncDbService() {return aysncDbService;}@Resourcepublic 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 usersetuserName=#{userName}where userId=#{userId}</update><delete id="delUser" parameterType="java.lang.Long">delete from userwhereuserId=#{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聊天室客户端