2017-07-07 59 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