项目启动时Spring aop不会运行

时间:2017-07-07 01:58:45

标签: spring-boot aop

我实现了一个spring-boot 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());
        }
    }
}

1 个答案:

答案 0 :(得分:0)

您需要完全限定注释,如下所示:

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

另外,正如我在上面的评论中所提到的,你需要在classpath上有spring-boot-starter-aop。也许你已经这样做了,但既然你没有说,那值得一提。

修改

我之前没有注意到真正的问题,我没有注意。

  1. 如果您从另一个类拨打电话,则只会触发Spring AOP。这是因为Spring需要能够拦截调用并运行切入点。从构造函数调用方法不会做任何事情。

  2. 你可以做一个hackish解决方法。在您的类(不是构造函数)中创建@PostConstruct void postConstruct() {}方法,自动装配ApplicationContext,然后在MyClassWithInitMethod myClass = context.getBean(MyClassWithInitMethod.class)方法中执行postConstruct。然后在myClass上调用方法,AOP将启动。

  3. 坦率地说,我以前没有检查你在切入点中做了什么,这是一个糟糕的主意。当多个线程运行时,它们将覆盖静态上下文,并创建一个竞争条件,然后您将创建另一个问题。 不要这样做!请改用工厂模式,然后将DataSourceFactory注入现在有注释的类中。