编写框架ssm总结

一.常见错误

  1. 反射调用失败
    通常是有成员变量没有注入成功,出现再AopHelper代理生成的时候
  2. 反射调用失败lang.IllegalArgumentException: argument type mismatch
            request获得的参数类型跟方法中的参数类型不一致
package com.hikvision.sro.core.config;

import com.google.common.collect.Maps;
import com.hikvision.sro.common.annotation.CacheDuration;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.cache.Cache;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Method;
import java.util.Map;
import java.util.Set;

import static com.google.common.collect.Sets.newHashSet;
import static org.springframework.core.annotation.AnnotationUtils.findAnnotation;
import static org.springframework.util.StringUtils.isEmpty;

/**
 * 新写了一个SpringRedisCacheManager,继承自RedisCacheManager,
 * 用于对@CacheDuration解析及有效期的设置
 * 程序初始化后即写入注解给定的过期时间
 * @author lobin
 * @date 2018/10/17
 */
public class SpringRedisCacheManager extends RedisCacheManager implements ApplicationContextAware, InitializingBean {
    private ApplicationContext applicationContext;
    private Map<String,Long> expireMap;
    public SpringRedisCacheManager(RedisTemplate redisTemplate) {
        super(redisTemplate);
    }
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
    @Override
    public void afterPropertiesSet() {
        /**
         * 获取所有CacheDuration注解的
         */
        expireMap= Maps.newHashMap();
        String[] beanNames = applicationContext.getBeanNamesForType(Object.class);
        for (String beanName : beanNames) {
            if(beanName.contains("com.hikvision.sro.services.client.BasicInfoService")){
                System.out.println(beanName);
            }
            final Class clazz = applicationContext.getType(beanName);
            ReflectionUtils.doWithMethods(clazz, method -> {
                ReflectionUtils.makeAccessible(method);
                CacheDuration cacheDuration = findCacheDuration(clazz, method);
                Cacheable cacheable = findAnnotation(method, Cacheable.class);
                CacheConfig cacheConfig = findAnnotation(clazz, CacheConfig.class);
                if(null==cacheDuration||null==cacheable){
                    return;
                }
                Set<String> cacheNames = findCacheNames(cacheConfig, cacheable);
                for (String cacheName : cacheNames) {
                    expireMap.put(cacheName, cacheDuration.duration());
                }
            }, method -> null != findAnnotation(method, Cacheable.class));

        }
        if(!expireMap.isEmpty()){
            super.setExpires(expireMap);
        }



    }
    /**
     * CacheDuration标注的有效期,优先使用方法上标注的有效期
     * @param clazz
     * @param method
     * @return
     */
    private CacheDuration findCacheDuration(Class clazz, Method method) {
        CacheDuration methodCacheDuration = findAnnotation(method, CacheDuration.class);
        if (null != methodCacheDuration) {
            return methodCacheDuration;
        }
        CacheDuration classCacheDuration = findAnnotation(clazz, CacheDuration.class);
        if (null != classCacheDuration) {
            return classCacheDuration;
        }
        return null;
    }
    private Set<String> findCacheNames(CacheConfig cacheConfig, Cacheable cacheable) {
        return isEmpty(cacheable.value()) ?
                newHashSet(cacheConfig.cacheNames()) : newHashSet(cacheable.value());
    }
    @Override
    protected Cache getMissingCache(String name) {
        long expiration = computeExpiration(name);
        return new CustomizedRedisCache(name,
                (this.isUsePrefix() ? this.getCachePrefix().prefix(name) : null),
                this.getRedisOperations(),
                expiration);
    }
}
package com.hikvision.sro.core.config;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.parser.ParserConfig;
import com.hikvision.sro.common.util.MD5;
import com.hikvision.sro.core.services.ThreadLocalUser;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.cache.interceptor.SimpleKeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import java.lang.reflect.Method;

/**
 * @author tongxiabin
 */
@Configuration
@EnableCaching
@EnableTransactionManagement(proxyTargetClass = true)
public class RedisConfig extends CachingConfigurerSupport {
    /**
     * 定义缓存数据 key 生成策略的bean
     * 包名+类名+方法名+所有参数
    */
    @Bean("wiselyKeyGenerator")
    public KeyGenerator withUserKeyGenerator(){
        return (target, method, params) -> {
            StringBuilder sb = new StringBuilder();
            sb.append(target.getClass().getName());
            sb.append(method.getName());
            sb.append(JSON.toJSONString(ThreadLocalUser.getUser()));
            sb.append(JSON.toJSONString(params));
            return MD5.encodeByMD5(sb.toString());
        };

    }

    /**
     * 公共缓存key生成,不区分用户
     * @return
     */
    @Bean("commonKeyGenerator")
    public KeyGenerator commonKeyGenerator() {
        return (Object target, Method method, Object... params) -> {
            StringBuilder sb = new StringBuilder();
            sb.append(target.getClass().getName());
            sb.append(method.getName());
            sb.append(JSON.toJSONString(params));
            return MD5.encodeByMD5(sb.toString());
        };
    }

    /**
     * 要启用spring缓存支持,需创建一个 CacheManager的 bean,CacheManager 接口有很多实现,这里Redis 的集成,用 RedisCacheManager这个实现类
     * Redis 不是应用的共享内存,它只是一个内存服务器,就像 MySql 似的,
     * 我们需要将应用连接到它并使用某种“语言”进行交互,因此我们还需要一个连接工厂以及一个 Spring 和 Redis 对话要用的 RedisTemplate,
     * 这些都是 Redis 缓存所必需的配置,把它们都放在自定义的 CachingConfigurerSupport 中
     */
    @Bean
    public CacheManager cacheManager(
            @SuppressWarnings("rawtypes") RedisTemplate redisTemplate) {
        RedisCacheManager cacheManager = new SpringRedisCacheManager(redisTemplate);
        cacheManager.setUsePrefix(true);
        //设置默认缓存时间为20min
        cacheManager.setDefaultExpiration(20*60L);
        return cacheManager;
    }

    /**
     * 显示声明缓存key生成器
     *
     * @return
     */
    @Override
    @Bean
    public KeyGenerator keyGenerator() {
        return new SimpleKeyGenerator();
    }


    //1.项目启动时此方法先被注册成bean被spring管理

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);

        FastJsonRedisSerializer<Object> fastJsonRedisSerializer = new FastJsonRedisSerializer<>(Object.class);
        // 全局开启AutoType
        ParserConfig.getGlobalInstance().setAutoTypeSupport(true);

        // 设置值(value)的序列化采用FastJsonRedisSerializer。
        redisTemplate.setValueSerializer(fastJsonRedisSerializer);
        redisTemplate.setHashValueSerializer(fastJsonRedisSerializer);
        // 设置键(key)的序列化采用StringRedisSerializer。
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());

        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }
}

package com.hikvision.sro.core.config;
 
import com.google.common.collect.Maps;
import com.hikvision.sro.common.annotation.CacheDuration;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.cache.Cache;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.ReflectionUtils;
 
import java.lang.reflect.Method;
import java.util.Map;
import java.util.Set;
 
import static com.google.common.collect.Sets.newHashSet;
import static org.springframework.core.annotation.AnnotationUtils.findAnnotation;
import static org.springframework.util.StringUtils.isEmpty;
 
/**
 * 新写了一个SpringRedisCacheManager,继承自RedisCacheManager,
 * 用于对@CacheDuration解析及有效期的设置
 * 程序初始化后即写入注解给定的过期时间
 * @author lobin
 * @date 2018/10/17
 */
public class SpringRedisCacheManager extends RedisCacheManager implements ApplicationContextAware, InitializingBean {
    private ApplicationContext applicationContext;
    private Map<String,Long> expireMap;
    public SpringRedisCacheManager(RedisTemplate redisTemplate) {
        super(redisTemplate);
    }
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
    @Override
    public void afterPropertiesSet() {
        /**
         * 获取所有CacheDuration注解的
         */
        expireMap= Maps.newHashMap();
        String[] beanNames = applicationContext.getBeanNamesForType(Object.class);
        for (String beanName : beanNames) {
            if(beanName.contains("com.hikvision.sro.services.client.BasicInfoService")){
                System.out.println(beanName);
            }
            final Class clazz = applicationContext.getType(beanName);
            ReflectionUtils.doWithMethods(clazz, method -> {
                ReflectionUtils.makeAccessible(method);
                CacheDuration cacheDuration = findCacheDuration(clazz, method);
                Cacheable cacheable = findAnnotation(method, Cacheable.class);
                CacheConfig cacheConfig = findAnnotation(clazz, CacheConfig.class);
                if(null==cacheDuration||null==cacheable){
                    return;
                }
                Set<String> cacheNames = findCacheNames(cacheConfig, cacheable);
                for (String cacheName : cacheNames) {
                    expireMap.put(cacheName, cacheDuration.duration());
                }
            }, method -> null != findAnnotation(method, Cacheable.class));
 
        }
        if(!expireMap.isEmpty()){
            super.setExpires(expireMap);
        }
 
 
 
    }
    /**
     * CacheDuration标注的有效期,优先使用方法上标注的有效期
     * @param clazz
     * @param method
     * @return
     */
    private CacheDuration findCacheDuration(Class clazz, Method method) {
        CacheDuration methodCacheDuration = findAnnotation(method, CacheDuration.class);
        if (null != methodCacheDuration) {
            return methodCacheDuration;
        }
        CacheDuration classCacheDuration = findAnnotation(clazz, CacheDuration.class);
        if (null != classCacheDuration) {
            return classCacheDuration;
        }
        return null;
    }
    private Set<String> findCacheNames(CacheConfig cacheConfig, Cacheable cacheable) {
        return isEmpty(cacheable.value()) ?
                newHashSet(cacheConfig.cacheNames()) : newHashSet(cacheable.value());
    }
    @Override
    protected Cache getMissingCache(String name) {
        long expiration = computeExpiration(name);
        return new CustomizedRedisCache(name,
                (this.isUsePrefix() ? this.getCachePrefix().prefix(name) : null),
                this.getRedisOperations(),
                expiration);
    }
}
 

猜你喜欢

转载自blog.csdn.net/qq_30869501/article/details/85172832
今日推荐