2017-07-07 84 views
0

我已經實現了Spring啓動aop演示並運行良好,但是當我想在項目啓動時使用它來加載某些資源時,它不會以某種方式運行項目啓動時Spring aop不運行

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(); 

    } 
} 

的VendorSource註釋:

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"; 
} 

它運行良好這裏,我可以成功地標註更改數據源:

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(); 
    } 
} 

,但它並不在這裏工作,AOP的方法不是在所有調用:

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

TestComponent可以成功初始化,它似乎使用默認的數據源,並且註釋根本不起作用 – Levy

+0

您是如何啓用AOP的? –

+0

帶有方面和組件註釋,彈簧引導將自動啓用它 – Levy

回答

0

您需要完全限定的註釋,像這樣:同樣

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

,正如我在上面的評論中提到的,你需要在類路徑上有spring-boot-starter-aop。也許你已經這樣做了,但由於你沒有說過,所以值得一提。

編輯

我之前沒有發現真正的問題,我沒注意。

  1. 如果您從另一個類進行調用,Spring AOP只會觸發。這是因爲Spring需要能夠攔截呼叫並運行切入點。從構造函數調用該方法不會執行任何操作。

  2. 你可以做一個hackish的解決方法。在類中創建一個@PostConstruct void postConstruct() {}方法(不是構造函數),自動裝入ApplicationContext,然後在postConstruct方法中執行MyClassWithInitMethod myClass = context.getBean(MyClassWithInitMethod.class)。然後調用該方法上myClass,和AOP會一命嗚呼。

坦率地說,我以前也沒檢查你在你的切入點在做什麼,這是一個可怕的想法。當多個線程運行時,它們將覆蓋靜態上下文,並創建一個競爭條件,然後您將創建另一個問題。 不要這樣做!改爲使用工廠模式,並在現在具有註釋的類中注入DataSourceFactory

+0

照你說的做,但init方法仍不能按預期工作,而控制器工作正常 – Levy

+0

'init'方法位於一個獨立包中的類中。你在掃描嗎? –

+0

是的,春季啓動爲我做,我可以看到這些網站已被打印''System.out.println(site.getSite())',但從另一個數據庫 – Levy