一、先写一个demo来概述Adivisor的简单使用步骤
实现步骤:
1、通过MethodBeforeAdivice接口实现前置增强处理
1 public class ServiceBeforeAdvisor implements MethodBeforeAdvice { 2 private Logger logger = Logger.getLogger(ServiceBeforeAdvisor.class); 3 @Override 4 public void before(Method method, Object[] args, Object target) 5 throws Throwable { 6 logger.info("启动事务"); 7 logger.info("连接点对象:"+target.getClass().getSimpleName()); 8 logger.info("连接点方法:"+method.getName()); 9 logger.info("连接点方法参数:"+args[0]); 10 11 } 12 13 }
2、使用<aop:advisor>标签织入增强处理
1 //注意:advisor要放在aspect前面 2 <bean id="userService" class="com.pb.service.UserService"></bean> 3 <bean id="serviceBeforeAdvisor" class="com.pb.aop.ServiceBeforeAdvisor"></bean> 4 <aop:config> 5 <aop:pointcut expression="execution(public * com.pb.service.*.*(..))" 6 id="servicePointcut"/> 7 <aop:advisor advice-ref="serviceBeforeAdvisor" pointcut-ref="servicePointcut"/> 8 </aop:config>
3、测试类型
1 public class Test { 2 public static void main(String[] args) { 3 ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext 4 ("applicationContext.xml"); 5 UserService service = (UserService)context.getBean("userService"); 6 service.addUser(new User()); 7 } 8 }
二、使用Adivisor来实现数据读写分离
实现步骤:
1、通过MethodBeforeAdivice接口实现前置增强处理
1 public class DataBaseAdvice implements MethodBeforeAdvice { 2 /** 3 * 日志计数器 4 */ 5 private final static Logger logger = LoggerFactory.getLogger(DataBaseAdvice.class); 6 /** 7 * 存储方法前缀 8 */ 9 private List<String> methodKey; 10 /** 11 * 是否打印日志:true-打印,false-不打印 12 */ 13 private boolean showLog = true; 14 15 public void before(Method method, Object[] objects, Object o) throws Throwable { 16 boolean write = true; 17 String methodName = method.getName().toLowerCase(); 18 //若方法前缀匹配成功,返回false 19 if (CollectionUtils.isNotEmpty(methodKey)) { 20 for (String key : methodKey) { 21 if (methodName.startsWith(key.toLowerCase())) { 22 write = false; 23 break; 24 } 25 } 26 } 27 28 if (write) { 29 DbContextHolder.setDbType(DbContextHolder.DB_TYPE_RW); 30 if (showLog) { 31 logger.info(method.getName()+"连接主库"); 32 } 33 }else { 34 DbContextHolder.setDbType(DbContextHolder.DB_TYPE_R); 35 if (showLog) { 36 logger.info(method.getName()+"连接从库"); 37 } 38 } 39 } 40 41 public List<String> getMethodKey() { 42 return methodKey; 43 } 44 45 public void setMethodKey(List<String> methodKey) { 46 this.methodKey = methodKey; 47 } 48 49 public boolean isShowLog() { 50 return showLog; 51 } 52 53 public void setShowLog(boolean showLog) { 54 this.showLog = showLog; 55 } 56 }
切换主从库的持有类
1 public class DbContextHolder { 2 3 /** 4 * 线程threadLocal 5 */ 6 private static ThreadLocal<String> contextHolder = new ThreadLocal<String>(); 7 /** 8 * 主库:执行读写操作 9 */ 10 public static String DB_TYPE_RW = "dataSourceMaster"; 11 /** 12 * 从库:执行读库操作 13 */ 14 public static String DB_TYPE_R = "dataSourceSlave"; 15 16 /** 17 * 默认是读写库 18 * @return 19 */ 20 public static String getDbType() { 21 String db = contextHolder.get(); 22 if (db == null) { 23 db = DB_TYPE_RW; 24 } 25 return db; 26 } 27 28 /** 29 * 置本线程的dbType 30 * @param str 31 */ 32 public static void setDbType(String str) { 33 contextHolder.set(str); 34 } 35 36 /** 37 * @Title: clearDBType 38 * @Description: 清理连接类型 39 */ 40 public static void clearDBType() { 41 contextHolder.remove(); 42 } 43 }
2、使用<aop:advisor>标签织入增强处理
1 <!-- 动态数据源 --> 2 <bean id="dynamicDataSource" class="com.alibaba.health.dao.dynamic.DynamicDataSource"> 3 <!-- 通过key-value关联数据源 --> 4 <property name="targetDataSources"> 5 <map> 6 <entry value-ref="dataSourceMaster" key="monitorDataSourceMaster"/> 7 <entry value-ref="dataSourceSlave" key="monitorDataSourceSlave"/> 8 </map> 9 </property> 10 <property name="defaultTargetDataSource" ref="dataSourceMaster"/> 11 </bean> 12 13 <!-- 通知器的具体实现:配置主从库读写分离:以select、query、find、count开头的方法走从库 --> 14 <bean id="DataBaseAdvice" class="com.aliaba.health.dao.dynamic.DataBaseAdvice"> 15 <property name="methodKey"> 16 <list> 17 <value>select</value> 18 <value>query</value> 19 <value>find</value> 20 <value>count</value> 21 </list> 22 </property> 23 <property name="showLog" value="false"/> 24 </bean> 25 26 <!-- 切面配置 --> 27 <aop:config> 28 <!-- 配置切点:第一个*表示匹配所有方法的返回值类型,.表示当前包下所有类的方法,..表示当前包下及此包下所有自爆中的所有类方法; 29 第二个*表示所有类名,第三个*表示所有方法名,(..)表示所有方法参数--> 30 <aop:pointcut expression="execution(* com.alibaba.health.dao..*.*(..))" id="cutPoint"/> 31 <!-- 定义通知器 --> 32 <aop:advisor advice-ref="DataBaseAdvice" pointcut-ref="cutPoint"/> 33 </aop:config>
此时就完成了主从数据库读写分离的代码和xml配置,尤其可见各种技术组件,在于是否能灵活运用。