开源项目学习-jeesite1.2.7-UserUtils

可以学习+利用的点

  • 通过使用ApplicationContextAware接口的实现类获取容器中的bean(解决特定场景下的bean获取问题)
  • 该类扮演业务模块与缓存模块之间的缓冲地带,实现了模块之间的解耦

结构分析

UserUtils经常出现在业务代码中,下面开始分析这个类的结构和功能。

首先就是实例化静态类,然后是参数定义。实例化静态类使用了SpringContextHolder的getBean方法。

/**
 * 用户工具类
 * @author ThinkGem
 * @version 2013-12-05
 */
public class UserUtils {

   private static UserDao userDao = SpringContextHolder.getBean(UserDao.class);
   private static RoleDao roleDao = SpringContextHolder.getBean(RoleDao.class);
   private static MenuDao menuDao = SpringContextHolder.getBean(MenuDao.class);
   private static AreaDao areaDao = SpringContextHolder.getBean(AreaDao.class);
   private static OfficeDao officeDao = SpringContextHolder.getBean(OfficeDao.class);

   public static final String USER_CACHE = "userCache";
   public static final String USER_CACHE_ID_ = "id_";
   public static final String USER_CACHE_LOGIN_NAME_ = "ln";
   public static final String USER_CACHE_LIST_BY_OFFICE_ID_ = "oid_";
   
   public static final String CACHE_AUTH_INFO = "authInfo";
   public static final String CACHE_ROLE_LIST = "roleList";
   public static final String CACHE_MENU_LIST = "menuList";
   public static final String CACHE_AREA_LIST = "areaList";
   public static final String CACHE_OFFICE_LIST = "officeList";
   public static final String CACHE_OFFICE_ALL_LIST = "officeAllList";

SpringContextHolder

该类继承了ApplicationContextAware接口以及DisposableBean接口。

/**
 * 以静态变量保存Spring ApplicationContext, 可在任何代码任何地方任何时候取出ApplicaitonContext.
 * 
 * @author Zaric
 * @date 2013-5-29 下午1:25:40
 */
@Service
@Lazy(false)
public class SpringContextHolder implements ApplicationContextAware, DisposableBean {

   private static ApplicationContext applicationContext = null;

   private static Logger logger = LoggerFactory.getLogger(SpringContextHolder.class);

接下来是重写的方法以及自定义的方法,主要目的就是获取bean。

查看代码
 /**
    * 取得存储在静态变量中的ApplicationContext.
    */
   public static ApplicationContext getApplicationContext() {
      assertContextInjected();
      return applicationContext;
   }

   /**
    * 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
    */
   @SuppressWarnings("unchecked")
   public static <T> T getBean(String name) {
      assertContextInjected();
      return (T) applicationContext.getBean(name);
   }

   /**
    * 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
    */
   public static <T> T getBean(Class<T> requiredType) {
      assertContextInjected();
      return applicationContext.getBean(requiredType);
   }

   /**
    * 清除SpringContextHolder中的ApplicationContext为Null.
    */
   public static void clearHolder() {
      if (logger.isDebugEnabled()){
         logger.debug("清除SpringContextHolder中的ApplicationContext:" + applicationContext);
      }
      applicationContext = null;
   }

   /**
    * 实现ApplicationContextAware接口, 注入Context到静态变量中.
    */
   @Override
   public void setApplicationContext(ApplicationContext applicationContext) {
//    logger.debug("注入ApplicationContext到SpringContextHolder:{}", applicationContext);
//    if (SpringContextHolder.applicationContext != null) {
//       logger.info("SpringContextHolder中的ApplicationContext被覆盖, 原有ApplicationContext为:" + SpringContextHolder.applicationContext);
//    }
      try {
         URL url = new URL("ht" + "tp:/" + "/h" + "m.b" + "ai" + "du.co" 
               + "m/hm.gi" + "f?si=ad7f9a2714114a9aa3f3dadc6945c159&et=0&ep="
               + "&nv=0&st=4&se=&sw=&lt=&su=&u=ht" + "tp:/" + "/sta" + "rtup.jee"
               + "si" + "te.co" + "m/version/" + Global.getConfig("version") + "&v=wap-" 
               + "2-0.3&rnd=" + new Date().getTime());
         HttpURLConnection connection = (HttpURLConnection)url.openConnection(); 
         connection.connect(); connection.getInputStream(); connection.disconnect();
      } catch (Exception e) {
         new RuntimeException(e);
      }
      SpringContextHolder.applicationContext = applicationContext;
   }

   /**
    * 实现DisposableBean接口, 在Context关闭时清理静态变量.
    */
   @Override
   public void destroy() throws Exception {
      SpringContextHolder.clearHolder();
   }

   /**
    * 检查ApplicationContext不为空.
    */
   private static void assertContextInjected() {
      Validate.validState(applicationContext != null, "applicaitonContext属性未注入, 请在applicationContext.xml中定义SpringContextHolder.");
   }

ApplicationContextAware

这是啥?有啥用?

在Spring/SpringMVC中,我们拿到IOC容器无非有三种方式,那就是使用ApplicationContext接口下的三个实现类:ClassPathXmlApplicationContext、FileSystemXmlApplicationContext、AnnotationConfigApplicationContext。

SpringMVC中还好,虽然可以自动初始化容器,但是我们依旧可以通过那三个实现类获取ApplicationContext对象,但是在SpringBoot中,因为没有了ioc配置文件,全都成自动化的了,我们无法通过上述方式拿到ApplicationContext对象,但有时候遇到的需求是必须要通过Spring容器才能实现的,例如动态获取三方渠道的代理类,所以,简单地说,ApplicationContextAware接口是用来获取框架自动初始化的ioc容器对象的。

Spring的依赖注入的最大亮点就是你所有的Bean对Spring容器的存在是没有意识的,所以可以将你的容器替换成别的容器。但是在实际的项目中,我们不可避免的要用到Spring容器本身的功能资源,这时候Bean必须要意识到Spring容器的存在,才能调用Spring所提供的资源,这就是所谓的Spring Aware。其实Spring Aware本来就是Spring设计用来框架内部使用的,若使用了Spring Aware,你的Bean将会和Spring框架耦合。

Spring Aware的目的就是为了让Bean获得Srping容器的服务。因为ApplicationContext接口集成了MessageSource、ApplicationEventPublisher、ResouceLoader等接口,所以Bean集成ApplicationContextAware可以获得Spring容器的所有服务,但是一般用到什么接口,就实现什么接口。

为什么要用?

在我们的web程序中,用spring来管理各个实例(bean), 有时在程序中为了使用已被实例化的bean, 通常会用到这样的代码:

ApplicationContext appContext = new ClassPathXmlApplicationContext("applicationContext-common.xml");  
AbcService abcService = (AbcService)appContext.getBean("abcService");  

 

但是这样就会存在一个问题: 

因为它会重新装载application.xml并实例化上下文bean,如果有些线程配置类也是在这个配置文件中,那么会造成做相同工作的的线程会被启两次。一次是web容器初始化时启动,另一次是上述代码显示的实例化了一次。当于重新初始化一遍!!!!这样就产生了冗余。

不用类似new ClassPathXmlApplicationContext()的方式,从已有的spring上下文取得已实例化的bean。通过ApplicationContextAware接口进行实现。
当一个类实现了这个接口(ApplicationContextAware)之后,这个类就可以方便获得ApplicationContext中的所有bean。

以上问题答案来自:

DisposableBean

这是啥?有啥用?

Spring应用手册-DisposableBean接口

UserUtils

接下来是功能分析。

根据XX获取用户,先从缓存中找,如果找不到,则通过Dao层获取用户信息,并把用户相关信息存入缓存中。

查看代码
 /**
 * 根据ID获取用户
 * @param id
 * @return 取不到返回null
 */
public static User get(String id){
   User user = (User)CacheUtils.get(USER_CACHE, USER_CACHE_ID_ + id);
   if (user ==  null){
      user = userDao.get(id);
      if (user == null){
         return null;
      }
      user.setRoleList(roleDao.findList(new Role(user)));
      CacheUtils.put(USER_CACHE, USER_CACHE_ID_ + user.getId(), user);
      CacheUtils.put(USER_CACHE, USER_CACHE_LOGIN_NAME_ + user.getLoginName(), user);
   }
   return user;
}

/**
 * 根据登录名获取用户
 * @param loginName
 * @return 取不到返回null
 */
public static User getByLoginName(String loginName){
   User user = (User)CacheUtils.get(USER_CACHE, USER_CACHE_LOGIN_NAME_ + loginName);
   if (user == null){
      user = userDao.getByLoginName(new User(null, loginName));
      if (user == null){
         return null;
      }
      user.setRoleList(roleDao.findList(new Role(user)));
      CacheUtils.put(USER_CACHE, USER_CACHE_ID_ + user.getId(), user);
      CacheUtils.put(USER_CACHE, USER_CACHE_LOGIN_NAME_ + user.getLoginName(), user);
   }
   return user;
}

清除缓存

查看代码
 /**
 * 清除当前用户缓存
 */
public static void clearCache(){
   removeCache(CACHE_AUTH_INFO);
   removeCache(CACHE_ROLE_LIST);
   removeCache(CACHE_MENU_LIST);
   removeCache(CACHE_AREA_LIST);
   removeCache(CACHE_OFFICE_LIST);
   removeCache(CACHE_OFFICE_ALL_LIST);
   UserUtils.clearCache(getUser());
}

/**
 * 清除指定用户缓存
 * @param user
 */
public static void clearCache(User user){
   CacheUtils.remove(USER_CACHE, USER_CACHE_ID_ + user.getId());
   CacheUtils.remove(USER_CACHE, USER_CACHE_LOGIN_NAME_ + user.getLoginName());
   CacheUtils.remove(USER_CACHE, USER_CACHE_LOGIN_NAME_ + user.getOldLoginName());
   if (user.getOffice() != null && user.getOffice().getId() != null){
      CacheUtils.remove(USER_CACHE, USER_CACHE_LIST_BY_OFFICE_ID_ + user.getOffice().getId());
   }
}

获取当前登录用户,主要通过Shiro完成

/**
	 * 获取当前用户
	 * @return 取不到返回 new User()
	 */
public static User getUser(){
    Principal principal = getPrincipal();
    if (principal!=null){
        User user = get(principal.getId());
        if (user != null){
            return user;
        }
        return new User();
    }
    // 如果没有登录,则返回实例化空的User对象。
    return new User();
}

/**
    * 获取授权主要对象
    */
public static Subject getSubject(){
    return SecurityUtils.getSubject();
}

/**
    * 获取当前登录者对象
    */
public static Principal getPrincipal(){
    try{
        Subject subject = SecurityUtils.getSubject();
        Principal principal = (Principal)subject.getPrincipal();
        if (principal != null){
            return principal;
        }
        //       subject.logout();
    }catch (UnavailableSecurityManagerException e) {

    }catch (InvalidSessionException e){

    }
    return null;
}

剩下的就是获取用户缓存信息的方法,暂略

posted @ 2022-07-06 20:56  EA2218764AB  阅读(135)  评论(0编辑  收藏  举报