使用spring aop+自定义注解实现动态使用DataSource

Spring AOP的两种实现方式:JDK动态代理和CGLIB动态代理
1、JDK动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。
2、CGLIB动态代理是利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。

1、如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP。
2、如果目标对象实现了接口,可以强制使用CGLIB实现AOP。
3、如果目标对象没有实现了接口,必须采用CGLIB库,spring会自动在JDK动态代理和CGLIB之间转换。

AOP用来封装横切关注点,具体可以在下面的场景中使用:
Authentication 权限
Caching 缓存
Context passing 内容传递
Error handling 错误处理
Lazy loading 懒加载
Debugging  调试
logging, tracing, profiling and monitoring 记录跟踪 优化 校准
Performance optimization 性能优化
Persistence  持久化
Resource pooling 资源池
Synchronization 同步
Transactions 事务

参考文章:
Spring AOP 实现原理 http://blog.csdn.net/moreevan/article/details/11977115
aop,spring aop,aspectj区别与联系  http://blog.csdn.net/pingnanlee/article/details/38845955
实例简述Spring AOP之对AspectJ语法的支持  http://blog.csdn.net/kkdelta/article/details/5515882
Spring之AOP AspectJ切入点语法详解 http://jinnianshilongnian.iteye.com/blog/1415606
Java之代理(jdk静态代理,jdk动态代理,cglib动态代理,aop,aspectj) http://blog.csdn.net/centre10/article/details/6847828
使用Spring进行面向切面编程(AOP) http://www.blogjava.net/supercrsky/articles/174368.html


aop配置:


	
		
		
	



自定义注解--query:

@Target({ METHOD })
@Retention(RUNTIME)
public @interface Query {

    DataSourceType[] dataSourceType() default DataSourceType.MASTER;

    QueryStrategy queryStrategy() default QueryStrategy.ONE;

}

自定义注解相关文档:
自定义注解  http://www.cnblogs.com/xing901022/p/3966799.html
Java自定义注解 http://blog.csdn.net/yixiaogang109/article/details/7328466
自定义注解入门 http://www.cnblogs.com/peida/archive/2013/04/24/3036689.html

Advice类--DataSourceAutoSwitchAdvice:

public class DataSourceAutoSwitchAdvice {

    public Object queryData(ProceedingJoinPoint joinPoint, Query query) throws Throwable {
        try {
            List resultList = new ArrayList();
            for (DataSourceType dataSourceType : query.dataSourceType()) {
                DataSourceTypeHolder.switchTo(dataSourceType);
                Object result = joinPoint.proceed();
                if (null == result) {
                    continue;
                }

                if (query.queryStrategy() == QueryStrategy.ONE) {
                    return result;
                } else {
                    resultList.add(result);
                }
            }

            return mergeResult(resultList);
        } finally {
            DataSourceTypeHolder.clear();
        }
    }

    @SuppressWarnings("rawtypes")
    private Object mergeResult(List resultList) {
        if (CollectionUtils.isEmpty(resultList)) {
            return null;
        }

        if (resultList.size() == 1) {
            return resultList.get(0);
        }

        Object mergedResult = null;
        Object firstResult = resultList.get(0);
        if (firstResult instanceof Collection) {
            for (Object result : resultList) {
                mergedResult = CollectionUtils.union((Collection) mergedResult, (Collection) result);
            }
            return mergedResult;
        }

        throw new DataSourceAutoSwitchException("Can't merge result: unsupported class=" + firstResult.getClass());
    }

} 
  

辅助类DataSourceTypeHolder和DataSourceType:

public abstract class DataSourceTypeHolder {
    private static ThreadLocal dataSourceTypeHolder = new ThreadLocal();

    public static void switchTo(DataSourceType dataSourceType) {
        dataSourceTypeHolder.set(dataSourceType);
    }

    public static DataSourceType getDataSourceType() {
        return dataSourceTypeHolder.get();
    }

    public static void clear() {
        dataSourceTypeHolder.remove();
    }

}


public enum DataSourceType {

    MASTER("master", "master db"),

    SLAVE("slave", "slave db"),

    ARCHIVE("archive", "archive db");

    /** The enumeration's code. */
    private String code;

    /** The enumeration's description. */
    private String desc;

    /**
     * @param code the enumeration's code
     * @param desc the enumeration's description
     */
    private DataSourceType(String code, String desc) {
        this.code = code;
        this.desc = desc;
    }

    /**
     * Get an enumeration by it's code.
     * 
     * @param code the enumeration's code
     * @return {@link DataSourceType}
     */
    public static DataSourceType getEnumByCode(String code) {
        if (StringUtils.isBlank(code)) {
            return null;
        }

        for (DataSourceType ele : values()) {
            if (StringUtils.equals(code, ele.getCode())) {
                return ele;
            }
        }

        return null;
    }

    /**
     * @return the code
     */
    public String getCode() {
        return code;
    }

    /**
     * @return the desc
     */
    public String getDesc() {
        return desc;
    }

}

定义实现的dao类:


		
			
				
				
				
			
		
	

DataSourceAutoSwitchSqlMapClientDaoSupport类代码如下:

public abstract class DataSourceAutoSwitchSqlMapClientDaoSupport {
    private DataSourceType                          defaultDataSourceType   = DataSourceType.MASTER;
    private final Map sqlMapClientTemplateMap = new HashMap();

    public SqlMapClientTemplate getSqlMapClientTemplate() {
        DataSourceType dataSourceType = DataSourceTypeHolder.getDataSourceType();
        if (null == dataSourceType) {
            dataSourceType = defaultDataSourceType;
        }

        SqlMapClientTemplate sqlMapClientTemplate = sqlMapClientTemplateMap.get(dataSourceType.getCode());
        Assert.notNull(sqlMapClientTemplate, "SqlMapClientTemplate does not exist: dataSourceType=" + dataSourceType.getCode());

        return sqlMapClientTemplate;
    }

    /**
     * @param defaultDataSourceType the defaultDataSourceType to set
     */
    public void setDefaultDataSourceType(String defaultDataSourceType) {
        DataSourceType dataSourceType = DataSourceType.getEnumByCode(defaultDataSourceType);
        Assert.notNull(dataSourceType, "defaultDataSourceType must not be null");
        this.defaultDataSourceType = dataSourceType;
    }

    /**
     * @param sqlMapClientTemplateMap the sqlMapClientTemplateMap to set
     */
    public void setSqlMapClientTemplateMap(Map sqlMapClientTemplateMap) {
        Assert.notEmpty(sqlMapClientTemplateMap, "sqlMapClientTemplateMap must not be empty");
        this.sqlMapClientTemplateMap.putAll(sqlMapClientTemplateMap);
    }

    public void setSqlMapClient(Map sqlMapClientMap) {
        Assert.notEmpty(sqlMapClientMap, "sqlMapClientMap must not be empty");
        for (Entry entry : sqlMapClientMap.entrySet()) {
            if (!this.sqlMapClientTemplateMap.containsKey(entry.getKey())) {
                this.sqlMapClientTemplateMap.put(entry.getKey(), new SqlMapClientTemplate(entry.getValue()));
            }
        }
    }

}

实现类PosterBlacklistDaoImpl中的方法如下:

@Query(dataSourceType = DataSourceType.SLAVE)
@SuppressWarnings("unchecked")
@Override
public List getPosterBlacklistStatisticsFromSlaveDB(int companyId) {
return getSqlMapClientTemplate().queryForList("PosterBlacklist.getPosterBlacklistStatistics", companyId);
}


你可能感兴趣的:(专业知识)