将依赖项注入到启动时加载的 @Configuration 类使用的 bean 本身的问题 [英] Issue with injecting a dependency into a bean itself used by a @Configuration class loaded on startup

查看:47
本文介绍了将依赖项注入到启动时加载的 @Configuration 类使用的 bean 本身的问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想要一个 @Configuration 类来操作 Spring bean 的 Map(这里的 bean 将是 Map 的值).

I want for a @Configuration class to manipulate a Map of Spring beans (here the beans will be the values for the Map).

此外,一些 Spring bean 会注入依赖项 - 例如 Spring Data Jpa 存储库.

Moreover, some Spring beans will have dependencies injected into them - such as Spring Data Jpa repositories.

我有以下配置类(MethodSecurityConfiguration):

I have the following configuration class (MethodSecurityConfiguration):

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class MethodSecurityConfiguration extends GlobalMethodSecurityConfiguration {

    @Override
    protected AuthenticationManager authenticationManager() {
        AuthenticationManager authenticationManager = new ProviderManager();
        return authenticationManager;
    }

    @Override
    protected MethodSecurityExpressionHandler createExpressionHandler() {
        DefaultMethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
        expressionHandler.setPermissionEvaluator(permissionEvaluator());
        return expressionHandler;
    }

    @Bean
    public ApplicationPermissionEvaluator permissionEvaluator() {
        return new ApplicationPermissionEvaluator(permissionMap());
    }

    private Map<String, Permission> permissionMap() {
        Map<String, Permission> map = new HashMap<>();
        map.put("updateAdvertisementIsAllowed", advertisementOwnerPermission());
        map.put("advertisementByIdOwnerPermission", advertisementByIdOwnerPermission());
        return map;
    }

    @Bean
    public AdvertisementOwnerPermission advertisementOwnerPermission() {
        return new AdvertisementOwnerPermission();
    }

    @Bean
    public AdvertisementByIdOwnerPermission advertisementByIdOwnerPermission() {
        return new AdvertisementByIdOwnerPermission();
    }

}

这将是上述 Map (AdvertisementByIdOwnerPermission) 的值:

This will be the value for the above Map (AdvertisementByIdOwnerPermission):

@Component
public class AdvertisementByIdOwnerPermission implements Permission {

    @Autowired
    private AdvertisementRepository advertisementRepository;

    @Override
    public boolean isAllowed(Authentication authentication, Object targetDomainObject) {
        boolean hasPermission = false;

        if (isId(targetDomainObject)) {
            Advertisement advertisement = advertisementRepository.findOne((Long) targetDomainObject);
            if (advertisement.getMember().getId().equals(((Member) authentication).getId())) {
                hasPermission = true;
            }
        }
        return hasPermission;
    }

    private boolean isId(Object targetDomainObject) {
        return targetDomainObject instanceof Long && (Long) targetDomainObject > 0;
    }

}

这是我在应用程序上下文启动时遇到的异常:

Here is the exception I get on application context startup:

Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire method: public void org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration.setPermissionEvaluator(java.util.List); nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'permissionEvaluator' defined in class path resource [com/bignibou/configuration/security/MethodSecurityConfiguration.class]: Instantiation of bean failed; nested exception is org.springframework.beans.factory.BeanDefinitionStoreException: Factory method [public com.bignibou.configuration.security.permission.ApplicationPermissionEvaluator com.bignibou.configuration.security.MethodSecurityConfiguration.permissionEvaluator()] threw exception; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'advertisementByIdOwnerPermission': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.bignibou.repository.advertisement.AdvertisementRepository com.bignibou.configuration.security.permission.AdvertisementByIdOwnerPermission.advertisementRepository; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.bignibou.repository.advertisement.AdvertisementRepository] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.inject(AutowiredAnnotationBeanPostProcessor.java:596)
    at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:87)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:289)
    ... 45 more
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'permissionEvaluator' defined in class path resource [com/bignibou/configuration/security/MethodSecurityConfiguration.class]: Instantiation of bean failed; nested exception is org.springframework.beans.factory.BeanDefinitionStoreException: Factory method [public com.bignibou.configuration.security.permission.ApplicationPermissionEvaluator com.bignibou.configuration.security.MethodSecurityConfiguration.permissionEvaluator()] threw exception; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'advertisementByIdOwnerPermission': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.bignibou.repository.advertisement.AdvertisementRepository com.bignibou.configuration.security.permission.AdvertisementByIdOwnerPermission.advertisementRepository; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.bignibou.repository.advertisement.AdvertisementRepository] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
    at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:597)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1094)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:989)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:504)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:475)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:304)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:300)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:195)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:1017)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:912)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:858)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.inject(AutowiredAnnotationBeanPostProcessor.java:553)
    ... 47 more
Caused by: org.springframework.beans.factory.BeanDefinitionStoreException: Factory method [public com.bignibou.configuration.security.permission.ApplicationPermissionEvaluator com.bignibou.configuration.security.MethodSecurityConfiguration.permissionEvaluator()] threw exception; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'advertisementByIdOwnerPermission': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.bignibou.repository.advertisement.AdvertisementRepository com.bignibou.configuration.security.permission.AdvertisementByIdOwnerPermission.advertisementRepository; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.bignibou.repository.advertisement.AdvertisementRepository] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:188)
    at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:586)
    ... 59 more
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'advertisementByIdOwnerPermission': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.bignibou.repository.advertisement.AdvertisementRepository com.bignibou.configuration.security.permission.AdvertisementByIdOwnerPermission.advertisementRepository; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.bignibou.repository.advertisement.AdvertisementRepository] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:292)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1185)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:537)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:475)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:304)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:300)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:195)
    at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:324)
    at com.bignibou.configuration.security.MethodSecurityConfiguration$$EnhancerBySpringCGLIB$$6fb58a27.advertisementByIdOwnerPermission(<generated>)
    at com.bignibou.configuration.security.MethodSecurityConfiguration.permissionMap(MethodSecurityConfiguration.java:47)
    at com.bignibou.configuration.security.MethodSecurityConfiguration.permissionEvaluator(MethodSecurityConfiguration.java:41)
    at com.bignibou.configuration.security.MethodSecurityConfiguration$$EnhancerBySpringCGLIB$$6fb58a27.CGLIB$permissionEvaluator$2(<generated>)
    at com.bignibou.configuration.security.MethodSecurityConfiguration$$EnhancerBySpringCGLIB$$6fb58a27$$FastClassBySpringCGLIB$$71f98c77.invoke(<generated>)
    at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:228)
    at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:312)
    at com.bignibou.configuration.security.MethodSecurityConfiguration$$EnhancerBySpringCGLIB$$6fb58a27.permissionEvaluator(<generated>)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:483)
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:166)
    ... 60 more
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.bignibou.repository.advertisement.AdvertisementRepository com.bignibou.configuration.security.permission.AdvertisementByIdOwnerPermission.advertisementRepository; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.bignibou.repository.advertisement.AdvertisementRepository] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:508)
    at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:87)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:289)
    ... 81 more
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.bignibou.repository.advertisement.AdvertisementRepository] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:1103)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:963)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:858)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:480)
    ... 83 more

谁能帮我配置我的应用程序,以便 AdvertisementByIdOwnerPermission 正确注入其依赖项?

Can anyone please help me configure my app so that the AdvertisementByIdOwnerPermission gets its dependency properly injected?

编辑 1:AdvertisementRepository 是 Spring 数据 Jpa 存储库,声明如下:

edit 1: AdvertisementRepository is a Spring data Jpa repository declared as follows:

RooJpaRepository:

RooJpaRepository:

@RooJpaRepository(domainType = Advertisement.class)
public interface AdvertisementRepository {

}

连同其 ITD:

privileged aspect AdvertisementRepository_Roo_Jpa_Repository {

    declare parents: AdvertisementRepository extends JpaRepository<Advertisement, Long>;

    declare parents: AdvertisementRepository extends JpaSpecificationExecutor<Advertisement>;

    declare @type: AdvertisementRepository: @Repository;

}

编辑 2:JPA 配置:

@Configuration
@EnableJpaRepositories(basePackages = "com.bignibou.repository")
public class JpaConfiguration {

}

public abstract class DataConfiguration {

    @Value("${database.driverClassName}")
    private String driverClassName;

    @Value("${database.url}")
    private String url;

    @Value("${database.username}")
    private String username;

    @Value("${database.password}")
    private String password;

    @Value("${database.validationQuery}")
    private String validationQuery;

    @Bean(destroyMethod = "close")
    public DataSource dataSource() {
        BasicDataSource dataSource = new BasicDataSource();
        dataSource.setDriverClassName(driverClassName);
        dataSource.setUrl(url);
        dataSource.setUsername(username);
        dataSource.setPassword(password);
        dataSource.setTestOnBorrow(Boolean.TRUE);
        dataSource.setTestOnReturn(Boolean.TRUE);
        dataSource.setTestWhileIdle(Boolean.TRUE);
        dataSource.setTimeBetweenEvictionRunsMillis(1800000);
        dataSource.setNumTestsPerEvictionRun(3);
        dataSource.setMinEvictableIdleTimeMillis(1800000);
        dataSource.setValidationQuery(validationQuery);
        dataSource.setMaxActive(5);
        dataSource.setLogAbandoned(Boolean.TRUE);
        dataSource.setRemoveAbandoned(Boolean.TRUE);
        dataSource.setRemoveAbandonedTimeout(10);
        return dataSource;
    }

    @Bean
    public JpaTransactionManager transactionManager() {
        JpaTransactionManager transactionManager = new JpaTransactionManager();
        transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
        return transactionManager;
    }

    @Bean
    public EntityManager entityManager() {
        return entityManagerFactory().getObject().createEntityManager();
    }

    @Bean
    public HibernateJpaVendorAdapter jpaVendorAdapter() {
        return new HibernateJpaVendorAdapter();
    }

    @Bean
    public HibernatePersistence persistenceProvider() {
        return new HibernatePersistence();
    }

    @Bean(name = "entityManagerFactory")
    public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
        LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
        entityManagerFactoryBean.setPackagesToScan("com.bignibou.domain");
        entityManagerFactoryBean.setDataSource(dataSource());
        entityManagerFactoryBean.setPersistenceProvider(persistenceProvider());
        entityManagerFactoryBean.setJpaVendorAdapter(jpaVendorAdapter());
        entityManagerFactoryBean.setJpaPropertyMap(propertiesMap());
        entityManagerFactoryBean.afterPropertiesSet();
        return entityManagerFactoryBean;
    }

    public abstract Map<String, String> propertiesMap();

    @Bean
    public HibernateExceptionTranslator hibernateExceptionTranslator() {
        return new HibernateExceptionTranslator();
    }

}

@Profile({ Profiles.DEFAULT, Profiles.CLOUD, Profiles.DEV })
@Configuration
@EnableTransactionManagement(mode = AdviceMode.ASPECTJ)
class DefaultDataConfiguration extends DataConfiguration {

    @Override
    public Map<String, String> propertiesMap() {
        Map<String, String> propertiesMap = new HashMap<>();
        propertiesMap.put("hibernate.dialect", "org.hibernate.dialect.MySQL5InnoDBDialect");
        propertiesMap.put("hibernate.hbm2ddl.auto", "update");
        propertiesMap.put("hibernate.ejb.naming_strategy", "org.hibernate.cfg.ImprovedNamingStrategy");
        propertiesMap.put("hibernate.connection.charSet", "UTF-8");
        propertiesMap.put("hibernate.show_sql", "true");
        propertiesMap.put("hibernate.format_sql", "true");
        propertiesMap.put("hibernate.use_sql_comments", "true");
        return propertiesMap;
    }

}

编辑 3:我更改了我的 MethodSecurityConfiguration 如下:

edit 3: I changed my MethodSecurityConfiguration as follows:

@Autowired//FAILS!!
private AdvertisementRepository advertisementRepository;

@Bean
public AdvertisementByIdOwnerPermission advertisementByIdOwnerPermission() {
    return new AdvertisementByIdOwnerPermission(advertisementRepository);
}

现在 AdvertisementByIdOwnerPermission 通过构造函数获取其依赖项.唯一需要解决的问题是 AdvertisementRepositoryMethodSecurityConfiguration 类尝试自动装配时尚未构建.有人可以帮我解决这个问题吗?

Now the AdvertisementByIdOwnerPermission takes its dependency through the constructor. The only issue to be resolved is that the AdvertisementRepository is not constructed yet by the time the MethodSecurityConfiguration class attempts to autowire it. Can someone please help me sort out this issue?

edit 4:我尝试将 @Order(2) 放入 MethodSecurityConfiguration 类,将 @Order(1) 放入 JpaConfiguration 类.我仍然有同样的问题...

edit 4: I tried placing @Order(2) to the MethodSecurityConfiguration class and @Order(1) to the JpaConfiguration class. I still have the same issue...

编辑5:使用@ComponentScan 注释的@Configuration 类:

edit 5: @Configuration class using the @ComponentScan annotation:

@Configuration
@EnableSpringConfigured
@ComponentScan(basePackages = { "com.bignibou" }, excludeFilters = { @Filter(type = FilterType.CUSTOM, value = RooRegexFilter.class),
        @Filter(type = FilterType.ANNOTATION, value = Controller.class) })
public class BaseConfiguration {
...

推荐答案

这很可能是使用旧版本的 Spring Data JPA 造成的.使用 1.4.2 时,您应该引入 Spring Data Commons 1.7.2,从而受益于我们在类型预测领域所做的一些改进.

This is very likely to be caused by using an older version of Spring Data JPA. When using 1.4.2 you should pull in Spring Data Commons 1.7.2 and thus benefit from a few improvements we made in the area of type prediction.

底线是:这应该适用于最新版本.

Bottom line is: this should work in the latest version.

这篇关于将依赖项注入到启动时加载的 @Configuration 类使用的 bean 本身的问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆