Maison > Java > javaDidacticiel > Explication détaillée de l'utilisation de Spring Aop pour implémenter la séparation en lecture-écriture de MySQL dans la couche métier

Explication détaillée de l'utilisation de Spring Aop pour implémenter la séparation en lecture-écriture de MySQL dans la couche métier

高洛峰
Libérer: 2017-01-24 10:49:31
original
1887 Les gens l'ont consulté

spring aop, la configuration maître-esclave mysql réalise la séparation lecture-écriture. Ensuite, j'enregistrerai mon processus de configuration et les problèmes rencontrés pour faciliter la prochaine opération, j'espère aussi aider quelques amis.

1. Utilisez le mécanisme d'interception Spring Aop pour sélectionner dynamiquement les sources de données.

import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
 * RUNTIME
 * 编译器将把注释记录在类文件中,在运行时 VM 将保留注释,因此可以反射性地读取。
 * @author yangGuang
 *
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface DataSource {
  String value();
}
Copier après la connexion

3. Utilisez AbstractRoutingDataSource de Spring pour résoudre le problème de plusieurs sources de données

import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
  
 public class ChooseDataSource extends AbstractRoutingDataSource {
  
   @Override
   protected Object determineCurrentLookupKey() {
     return HandleDataSource.getDataSource();
   }
     
 }
Copier après la connexion


4. Utilisez ThreadLocal pour résoudre le problème de sécurité des threads.

public class HandleDataSource {
  public static final ThreadLocal<String> holder = new ThreadLocal<String>();
  public static void putDataSource(String datasource) {
    holder.set(datasource);
  }
    
  public static String getDataSource() {
    return holder.get();
  }  
}
Copier après la connexion


5. Définissez une classe d'aspect de source de données, accédez-y via aop et configurez-la dans le fichier de configuration Spring, afin que les annotations aop ne soient pas utilisées.

import java.lang.reflect.Method;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
//@Aspect
//@Component
public class DataSourceAspect {
  //@Pointcut("execution(* com.apc.cms.service.*.*(..))") 
  public void pointCut(){}; 
    
 // @Before(value = "pointCut()")
   public void before(JoinPoint point)
    {
      Object target = point.getTarget();
      System.out.println(target.toString());
      String method = point.getSignature().getName();
      System.out.println(method);
      Class<?>[] classz = target.getClass().getInterfaces();
      Class<?>[] parameterTypes = ((MethodSignature) point.getSignature())
          .getMethod().getParameterTypes();
      try {
        Method m = classz[0].getMethod(method, parameterTypes);
        System.out.println(m.getName());
        if (m != null && m.isAnnotationPresent(DataSource.class)) {
          DataSource data = m.getAnnotation(DataSource.class);
          HandleDataSource.putDataSource(data.value());
        }
          
      } catch (Exception e) {
        e.printStackTrace();
      }
    }
}
Copier après la connexion


6. Configurez applicationContext.xml

<!-- 主库数据源 -->
 <bean id="writeDataSource" class="com.jolbox.bonecp.BoneCPDataSource" destroy-method="close">
  <property name="driverClass" value="com.mysql.jdbc.Driver"/>
  <property name="jdbcUrl" value="jdbc:mysql://172.22.14.6:3306/cpp?autoReconnect=true"/>
  <property name="username" value="root"/>
  <property name="password" value="root"/>
  <property name="partitionCount" value="4"/>
  <property name="releaseHelperThreads" value="3"/>
  <property name="acquireIncrement" value="2"/>
  <property name="maxConnectionsPerPartition" value="40"/>
  <property name="minConnectionsPerPartition" value="20"/>
  <property name="idleMaxAgeInSeconds" value="60"/>
  <property name="idleConnectionTestPeriodInSeconds" value="60"/>
  <property name="poolAvailabilityThreshold" value="5"/>
</bean>
  
<!-- 从库数据源 -->
<bean id="readDataSource" class="com.jolbox.bonecp.BoneCPDataSource" destroy-method="close">
  <property name="driverClass" value="com.mysql.jdbc.Driver"/>
  <property name="jdbcUrl" value="jdbc:mysql://172.22.14.7:3306/cpp?autoReconnect=true"/>
  <property name="username" value="root"/>
  <property name="password" value="root"/>
  <property name="partitionCount" value="4"/>
  <property name="releaseHelperThreads" value="3"/>
  <property name="acquireIncrement" value="2"/>
  <property name="maxConnectionsPerPartition" value="40"/>
  <property name="minConnectionsPerPartition" value="20"/>
  <property name="idleMaxAgeInSeconds" value="60"/>
  <property name="idleConnectionTestPeriodInSeconds" value="60"/>
  <property name="poolAvailabilityThreshold" value="5"/>
</bean>
  
<!-- transaction manager, 事务管理 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
  <property name="dataSource" ref="dataSource" />
</bean>
  
  
<!-- 注解自动载入 -->
<context:annotation-config />
  
<!--enale component scanning (beware that this does not enable mapper scanning!)-->
<context:component-scan base-package="com.apc.cms.persistence.rdbms" />
<context:component-scan base-package="com.apc.cms.service">
 <context:include-filter type="annotation" 
    expression="org.springframework.stereotype.Component" /> 
</context:component-scan> 
  
<context:component-scan base-package="com.apc.cms.auth" />
  
<!-- enable transaction demarcation with annotations -->
<tx:annotation-driven />
  
  
<!-- define the SqlSessionFactory -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
  <property name="dataSource" ref="dataSource" />
  <property name="typeAliasesPackage" value="com.apc.cms.model.domain" />
</bean>
  
<!-- scan for mappers and let them be autowired -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
  <property name="basePackage" value="com.apc.cms.persistence" />
  <property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>
  
<bean id="dataSource" class="com.apc.cms.utils.ChooseDataSource">
  <property name="targetDataSources"> 
     <map key-type="java.lang.String"> 
       <!-- write -->
       <entry key="write" value-ref="writeDataSource"/> 
       <!-- read -->
       <entry key="read" value-ref="readDataSource"/> 
     </map> 
       
  </property> 
  <property name="defaultTargetDataSource" ref="writeDataSource"/> 
</bean>
   
<!-- 激活自动代理功能 -->
<aop:aspectj-autoproxy proxy-target-class="true"/>
  
<!-- 配置数据库注解aop -->
<bean id="dataSourceAspect" class="com.apc.cms.utils.DataSourceAspect" />
<aop:config>
  <aop:aspect id="c" ref="dataSourceAspect">
    <aop:pointcut id="tx" expression="execution(* com.apc.cms.service..*.*(..))"/>
    <aop:before pointcut-ref="tx" method="before"/>
  </aop:aspect>
</aop:config>
<!-- 配置数据库注解aop -->
Copier après la connexion

7. Utilisez des annotations pour sélectionner dynamiquement les sources de données et lire et écrire respectivement des bibliothèques.

@DataSource("write")
public void update(User user) {
  userMapper.update(user);
}
  
@DataSource("read")
public Document getDocById(long id) {
  return documentMapper.getById(id);
}
Copier après la connexion

Testez l'opération d'écriture : vous pouvez modifier les données via l'application, modifier les données de la base de données principale et constater que les données de la base de données esclave sont mises à jour de manière synchrone, de sorte que les opérations d'écriture définies sont toutes écrites à la base de données

Testez l'opération de lecture : modifiez les données de la base de données esclave en arrière-plan, vérifiez que les données de la base de données principale n'ont pas été modifiées, actualisez la page de l'application et constatez que le les données de la base de données esclave sont lues, indiquant que la séparation de la lecture et de l'écriture est correcte.

Résumé des problèmes rencontrés :

Problème 1 : Le projet est un projet maven et utilise le mécanisme Spring aop En plus du package jar de base de spring, il doit également. utilisez le package jar Il y a aspectj.jar, aspectjweaver.jar et aopalliance.jar. Vérifiez le pom dans le projet et constatez que le package de dépendances est manquant. Puisque l'entrepôt local n'a pas ces jars, recherchez la bibliothèque centrale maven qui. peut permettre le téléchargement de packages jar, le configurer dans maven et mettre à jour automatiquement :

<repository>
   <id>nexus</id>
   <name>nexus</name>
   <url>http://repository.sonatype.org/content/groups/public/</url>
   <layout>default</layout>
 </repository>
Copier après la connexion


Configurez les jars dont dépend le projet, principalement parce que ces deux-là sont manquants.

  <dependency>
    <groupId>aspectj</groupId>
    <artifactId>aspectjrt</artifactId>
    <version>1.5.4</version>
</dependency>
<dependency>
    <groupId>aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.5.4</version>
lt;/dependency>
Copier après la connexion


Ce qui précède représente l'intégralité du contenu de cet article. J'espère qu'il sera utile à l'apprentissage de chacun, et j'espère également que tout le monde soutiendra le site Web PHP chinois. .

Pour des explications plus détaillées sur l'utilisation de Spring Aop pour implémenter la séparation de lecture et d'écriture MySQL dans la couche métier, veuillez faire attention au site Web PHP chinois pour les articles connexes !

Étiquettes associées:
source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal