Spring标签@Aspect-实现面向方向编程(@Aspect的多数据源自动加载)——SKY

   从Spring 2.0开始,可以使用基于schema及@AspectJ的方式来实现AOP。由于@Aspect是基于注解的,因此要求支持注解的5.0版本以上的JDK。

 环境要求:
    1. mybits的DB连接,实现动态多数据源的设置。
    2. service层实现数据访问。

 我们的目标是,如果用户调用Service层中任一方法,都配置其动态数据源Id。

 

在此先来说一下AOP:

    AOP(Aspect-OrientedProgramming,面向方面编程),可以说是OOP(Object-Oriented Programing,面向对象编程)的补充和完善。OOP引入封装、继承和多态性等概念来建立一种对象层次结构,用以模拟公共行为的一个集合。当我们需要为分散的对象引入公共行为的时候,OOP则显得无能为力。也就是说,OOP允许你定义从上到下的关系,但并不适合定义从左到右的关系。例如日志功能。日志代码往往水平地散布在所有对象层次中,而与它所散布到的对象的核心功能毫无关系。对于其他类型的代码,如安全性、异常处理和透明的持续性也是如此。这种散布在各处的无关的代码被称为横切(cross-cutting)代码,在OOP设计中,它导致了大量代码的重复,而不利于各个模块的重用。

简介

  前段时间写的java设计模式--代理模式,最近在看Spring Aop的时候,觉得于代理模式应该有密切的联系,于是决定了解下Spring Aop的实现原理。

  说起AOP就不得不说下OOP了,OOP中引入封装、继承和多态性等概念来建立一种对象层次结构,用以模拟公共行为的一个集合。但是,如果我们需要为部分对象引入公共部分的时候,OOP就会引入大量重复的代码。例如:日志功能。

  AOP技术利用一种称为“横切”的技术,解剖封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,这样就能减少系统的重复代码,降低模块间的耦合度,并有利于未来的可操作性和可维护性。AOP把软件系统分为两个部分:核心关注点和横切关注点。业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点。横切关注点的一个特点是,他们经常发生在核心关注点的多处,而各处都基本相似。比如权限认证、日志、事务处理。

 

下面说说@aspect实现的动态数据源配置:

1.定义一个Aspect。

    必须使用@Aspect在类名之前注解。

    当用户调用com.accessor.service包中任一类的任一方法,在调用前,Spring将自动执行下面的doBefore()方法,以及Doafter()方法。

这里数据源的选择是通过枚举实现的。

 1 /**
 2  * Created by Administrator on 2016/11/3.
 3  */
 4 @Component
 5 @Aspect
 6 public class MultipleDataSourceAspect{
 7     private static AtomicInteger counter = new AtomicInteger(0);
 8 
 9     @Before("execution(* com.accessor.service..*(..))")
10     public void doBefore(JoinPoint joinPoint) throws Throwable {
11         String className = joinPoint.getTarget().getClass().getName();
12         if (className.contains("oracle")) {
13             DataSourceContextHolder.setDataSourceType(DataSourceEnum.ORACLE_READ.getValue());
14         } else if (className.contains("sqlserver")) {
15             setMsDataSource(joinPoint.getArgs());
16         }
17         System.out.println("------------------begin"+counter.getAndIncrement() +"-----" + DataSourceContextHolder.getDataSourceType() + "--------thread:" + Thread.currentThread().getName()) ;
18     }
19     @After("execution(* com.accessor.service..*(..))")
20     public void doAfter(JoinPoint joinPoint) throws Throwable {
21         Object[] args = joinPoint.getArgs();
22         if (args != null && args.length > 0) {
23             if (args[0] instanceof Map) {
24                 Map param = (Map) args[0];
25                 param.remove("msHisFlag");
26                 param.remove("tabNameSuffix");
27             }
28         }
29         System.out.println("--------------------end------------------remove:" + DataSourceContextHolder.getDataSourceType());
30         DataSourceContextHolder.clearDataSourceType();
31     }
32 
33     //设置ms数据源
34     private void setMsDataSource(Object[] args) {
35         DataSourceEnum dataSourceEnum = null;
36         if (args != null && args.length > 0) {
37             if (args[0] instanceof Map) {
38                 Map param = (Map) args[0];
39                 String fundId = CommonUtil.convert(param.get("fundId"), String.class);
40                 if (fundId != null) {
41                     if ("1".equals(param.get("msHisFlag"))) {
42                         String tabNameSuffix = DateUtil.dateToStr(new Date(), "_yyyy_MM");
43                         param.put("tabNameSuffix", tabNameSuffix);
44                         dataSourceEnum = CommonUtil.getMsDataSourceEnum(fundId, true);
45                     } else {
46                         dataSourceEnum = CommonUtil.getMsDataSourceEnum(fundId);
47                     }
48                 }
49                 DataSourceContextHolder.setDataSourceType(dataSourceEnum.getValue());
50             }
51         }
52 
53         if (dataSourceEnum == null) {
54             throw new RuntimeException("无法确定查询的sqlserver数据源");
55         }
56     }
57 }
View Code

2.spring的文件配置

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <beans xmlns="http://www.springframework.org/schema/beans"
 3        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4        xmlns:aop="http://www.springframework.org/schema/aop"
 5        xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="
 6                       http://www.springframework.org/schema/beans
 7                       http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
 8                       http://www.springframework.org/schema/context
 9                       http://www.springframework.org/schema/context/spring-context-3.2.xsd
10                       http://www.springframework.org/schema/aop
11                       http://www.springframework.org/schema/aop/spring-aop-3.1.xsd">
12 
13 
14     <!-- 自动扫描(自动注入) -->
15     <context:annotation-config/>
16     <context:component-scan base-package="com.eastmoney"/>
17     <aop:aspectj-autoproxy proxy-target-class="true"/>
18 
19     <bean id="springContextUtil " class="com.eastmoney.accessor.util.SpringContextUtil"/>
20 
21     <!-- 引入mybatis属性配置文件 -->
22     <import resource="spring-mybatis.xml"/>
23 </beans>
View Code

3.mybatis的文件配置

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <beans xmlns="http://www.springframework.org/schema/beans"
 3        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4        xmlns:tx="http://www.springframework.org/schema/tx"
 5        xsi:schemaLocation="http://www.springframework.org/schema/beans
 6                            http://www.springframework.org/schema/beans/spring-beans.xsd
 7                            http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
 8 
 9     <!-- 动态数据源 -->
10     <bean id="dataSource" class="com.eastmoney.accessor.datasource.DynamicDataSource">
11         <property name="dsConfigFile" value="dataSource.xml"/>
12     </bean>
13 
14     <!-- mybatis配置 -->
15     <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
16         <property name="dataSource" ref="dataSource"/>
17         <property name="mapperLocations" value="classpath*:mapper/*/*.xml"/>
18         <property name="configLocation" value="classpath:/mybatis-config.xml"/>
19     </bean>
20 
21     <!-- 自动创建映射器,不用单独为每个 mapper映射-->
22     <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
23         <property name="basePackage" value="com.eastmoney.accessor.mapper"/>
24         <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
25     </bean>
26 
27     <!-- 事务管理器配置,单数据源事务 -->
28     <bean id="transactionManager"
29           class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
30         <property name="dataSource" ref="dataSource"/>
31     </bean>
32 
33     <tx:annotation-driven transaction-manager="transactionManager"/>
34 
35 </beans>
View Code

就这么简单而强大的Spring注解配置,非常感兴趣,下次去过一遍Spring的原理和注解的使用规则,有机会在和大家分享。

 

                                                                                                                                                                                           笔者:SKY-yong    2016/11/18

 

 

  

posted @ 2016-11-18 13:21  Sky—yong  阅读(1415)  评论(0编辑  收藏  举报