2017-07-07 5 views
0

Ich habe eine Spring-Boot-AOP-Demo implementiert und es läuft gut, aber wenn ich es verwenden möchte, um einige Ressourcen zu laden, wenn das Projekt startet, funktioniert es irgendwie nichtSpring AOP läuft nicht, wenn das Projekt startet

Aop:

package com.neo.mysql; 

import org.aspectj.lang.JoinPoint; 
import org.aspectj.lang.annotation.After; 
import org.aspectj.lang.annotation.Aspect; 
import org.aspectj.lang.annotation.Before; 
import org.aspectj.lang.reflect.MethodSignature; 
import org.springframework.stereotype.Component; 

import java.lang.reflect.Method; 

/** 
* Created by li_weia on 2017/7/6. 
*/ 
@Aspect 
@Component 
public class DynamicDataSourceAspect { 

    @Before("@annotation(VendorSource)") 
    public void beforeSwitchDS(JoinPoint point){ 

     //获得当前访问的class 
     Class<?> className = point.getTarget().getClass(); 

     //获得访问的方法名 
     String methodName = point.getSignature().getName(); 
     //得到方法的参数的类型 
     Class[] argClass = ((MethodSignature)point.getSignature()).getParameterTypes(); 
     String dataSource = DataSourceContextHolder.DEFAULT_DS; 
     try { 
      // 得到访问的方法对象 
      Method method = className.getMethod(methodName, argClass); 

      // 判断是否存在@DS注解 
      if (method.isAnnotationPresent(VendorSource.class)) { 
       VendorSource annotation = method.getAnnotation(VendorSource.class); 
       // 取出注解中的数据源名 
       dataSource = annotation.value(); 
      } 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 

     // 切换数据源 
     DataSourceContextHolder.setDB(dataSource); 

    } 


    @After("@annotation(VendorSource)") 
    public void afterSwitchDS(JoinPoint point){ 

     DataSourceContextHolder.clearDB(); 

    } 
} 

Die VendorSource Anmerkung:

package com.neo.mysql; 

import java.lang.annotation.ElementType; 
import java.lang.annotation.Retention; 
import java.lang.annotation.RetentionPolicy; 
import java.lang.annotation.Target; 

/** 
* Created by li_weia on 2017/7/6. 
*/ 
@Target({ ElementType.METHOD, ElementType.TYPE }) 
@Retention(RetentionPolicy.RUNTIME) 
public @interface VendorSource { 
    String value() default "vendor-master"; 
} 

Es ist gut hier läuft, ich Datenquelle erfolgreich durch Annotation ändern können:

package com.neo.web; 

import com.neo.entity.SiteEntity; 
import com.neo.mapper.ClassMappingDao; 
import com.neo.mysql.VendorSource; 
import org.springframework.beans.factory.annotation.Autowired; 
import org.springframework.web.bind.annotation.RequestMapping; 
import org.springframework.web.bind.annotation.RestController; 

import java.util.List; 

@RestController 
public class UserController { 

    private final ClassMappingDao siteMapper; 

    @Autowired(required = false) 
    public UserController(ClassMappingDao siteMapper) { 
     this.siteMapper = siteMapper; 
    } 

    @RequestMapping("/getSites") 
    @VendorSource("vendor-read") 
    public List<SiteEntity> getUsers() { 
     return siteMapper.getAllSite(); 
    } 
} 

aber es funktioniert hier nicht, wird die AOP-Methode überhaupt nicht aufgerufen:

package com.neo.component; 

import com.neo.entity.SiteEntity; 
import com.neo.mapper.ClassMappingDao; 
import com.neo.mysql.VendorSource; 
import org.springframework.beans.factory.annotation.Autowired; 
import org.springframework.stereotype.Component; 

import java.util.List; 

/** 
* Created by li_weia on 2017/7/7. 
*/ 
@Component 
public class TestComponent{ 
    private final ClassMappingDao userMapper; 

    @Autowired(required = false) 
    public TestComponent(ClassMappingDao userMapper) { 
     this.userMapper = userMapper; 
     init(); 
    } 

    @VendorSource("vendor-read") 
    public void init() { 
     List<SiteEntity> sites = userMapper.getAllSite(); 
     for(SiteEntity site: sites){ 
      System.out.println(site.getSite()); 
     } 
    } 
} 
+0

Die TestComponent kann erfolgreich initialisiert werden, es scheint, als ob die Standarddatenquelle verwendet wird und die Annotation überhaupt nicht funktioniert – Levy

+0

Wie haben Sie AOP aktiviert? –

+0

mit Aspect und Component Annotation, Spring Boot wird es automatisch aktivieren – Levy

Antwort

0

Sie müssen die Anmerkung vollständig zu qualifizieren, etwa so:

@Before("execution(public * *(..)) && @annotation(com.neo.mysql.VendorSource)") 
private void whatever() {} 

Auch Wie in meinem Kommentar oben erwähnt, müssen Sie spring-boot-starter-aop auf Classpath haben. Vielleicht tust du es schon, aber da du es nicht gesagt hast, ist es erwähnenswert.

bearbeiten:

Ich habe nicht bemerkt, das eigentliche Problem, bevor ich nicht die Aufmerksamkeit schenkte.

  1. Spring AOP wird nur ausgelöst, wenn Sie von einer anderen Klasse aus anrufen. Dies liegt daran, dass Spring in der Lage sein muss, den Aufruf abzufangen und den Pointcut auszuführen. Das Aufrufen der Methode aus dem Konstruktor wird nichts bewirken.

  2. Sie können einen hackish Workaround durchführen. Erstellen Sie eine @PostConstruct void postConstruct() {} Methode in Ihrer Klasse (nicht Konstruktor), autowire ApplicationContext, und dann MyClassWithInitMethod myClass = context.getBean(MyClassWithInitMethod.class) in der postConstruct Methode. Dann rufen Sie die Methode auf myClass und AOP wird kick.

Ehrlich gesagt, habe ich nicht vorher überprüfen, was Sie in Ihrem pointcut tun, und es ist eine schreckliche Idee. Wenn mehrere Threads ausgeführt werden, überschreiben sie den statischen Kontext und erstellen eine Race-Bedingung, für die Sie dann eine weitere Frage erstellen. Tu es nicht! Verwenden Sie stattdessen das Fabrikmuster und injizieren Sie die DataSourceFactory in die Klassen, die jetzt die Anmerkung haben.

+0

tat, wie Sie sagen, aber die init Methode funktioniert immer noch nicht wie erwartet, während der Controller gut funktioniert – Levy

+0

Die 'init'-Methode ist in einer Klasse, die in einem separaten Paket ist. Scannen Sie es? –

+0

Ja, Spring Boot macht es für mich, und ich kann sehen, die Seiten wurden von 'System.out.println (site.getSite())' 'gedruckt, aber aus einer anderen Datenbank – Levy