简体   繁体   English

为什么我无法在 Spring 引导的 Spring 上下文中获得我的 Bean 定义?

[英]Why am I not able to get my Bean definition available in my Spring context with Spring Boot?

I'm feeling stupid to ask this, but I can't understand where I'm wrong with my code.问这个我感觉很愚蠢,但我不明白我的代码哪里错了。

The context is:上下文是:

  • a Spring Boot application (1.5.7) with an embedded Jetty server and a controller to expose some endpoints带有嵌入式 Jetty 服务器的 Spring 引导应用程序 (1.5.7) 和 controller 以公开一些端点
  • a unique @Configuration class, where some of my beans are defined (Singleton and Prototype scopes)一个独特的@Configuration class,其中定义了我的一些 bean(单例和原型范围)
  • a @Service that uses some beans defined in my @Configuration class使用我的@Configuration class 中定义的一些bean 的@Service

The problem is:问题是:

  • a NoSuchBeanDefinitionException for one of my @Configuration bean.我的一个 @Configuration bean 的 NoSuchBeanDefinitionException。

Now the details:现在细节:

My SpringBootApplication:我的 SpringBoot 应用程序:

@SpringBootApplication
public class HbbTVApplication {
    public static void main(String[] args) {
        SpringApplication.run(HbbTVApplication.class, args);
    }
}

My @Configuration class:我的@配置 class:

@Configuration
@Profile(value = { "dev", "int", "pre", "pro" })
public class StandaloneFrontalConfig extends WebMvcConfigurerAdapter {

@Value("${kafka.bootstrap-servers}")
private String bootstrapServers;

@Bean
public Map<String, Object> producerConfigs() {
    Map<String, Object> props = new HashMap<>();
    props.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers);
    props.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
    props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
    return props;
}

@Bean
public ProducerFactory<String, String> producerFactory() {
    return new DefaultKafkaProducerFactory<>(producerConfigs());
}

@Bean
public KafkaTemplate<String, String> kafkaTemplate() {
    return new KafkaTemplate<>(producerFactory());
}

@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
    registry.addResourceHandler("/**").addResourceLocations("classpath:/standalone/");
}

@Bean
public WebMvcConfigurer corsConfigurer() {
    return new WebMvcConfigurerAdapter() {
        @Override
        public void addCorsMappings(CorsRegistry registry) {
            registry.addMapping("/**").allowedOrigins("*").allowedHeaders("*");
        }
    };
}

@Scope(value = ConfigurableBeanFactory.SCOPE_SINGLETON)
@Bean
public Security securityManager() {
    return new Security();
}

@Bean
@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public KngAflow getTechnicalCookie() {
    return new KngAflow();
}

@Bean
public EmbeddedServletContainerCustomizer customizer() {
    return new EmbeddedServletContainerCustomizer() {

        @Override
        public void customize(ConfigurableEmbeddedServletContainer container) {
            if (container instanceof JettyEmbeddedServletContainerFactory) {
                customizeJetty((JettyEmbeddedServletContainerFactory) container);
            }
        }

        private void customizeJetty(JettyEmbeddedServletContainerFactory jetty) {
            jetty.addServerCustomizers(new JettyServerCustomizer() {

                @Override
                public void customize(Server server) {
                    for (Connector connector : server.getConnectors()) {
                        if (connector instanceof ServerConnector) {
                            HttpConnectionFactory connectionFactory = ((ServerConnector) connector)
                                    .getConnectionFactory(HttpConnectionFactory.class);
                            connectionFactory.getHttpConfiguration().setCookieCompliance(CookieCompliance.RFC2965);
                        }
                    }
                }
            });
        }
    };
}
}

My @Service:我的@服务:

@Service
public class CookieService implements services.CookieService, InitializingBean {

    /**
     * Serializable
     */
    private static final long serialVersionUID = -1997257884335775587L;

    @Autowired
    ApplicationContext app;

    @Override
    public Cookie createTechnicalCookie() {
        return new Cookie(app.getBean(KngAflow.class), null);
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        if (app != null) {
            for (String bean : app.getBeanDefinitionNames()) {
                System.out.println("Bean: " + bean);
            }
        }
    }
}

And the "non defined" bean:和“未定义”的bean:

@JsonInclude(Include.NON_NULL)
@JsonIgnoreProperties({ "security", "maxAge", "domain", "updated" })
public class KngAflow implements Serializable, InitializingBean {

    @JsonProperty(value = "did")
    private String did;
    @JsonProperty(value = "checksum")
    private String checksum;
    @Autowired
    private Security security;
    private Integer maxAge;
    private String domain;
    private boolean updated = false;

    public KngAflow() {
        domain = ".mydomain.com";
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        did = UUID.randomUUID().toString();
        maxAge = 365 * 24 * 60 * 60;
        checksum = security.encrypt(did + security.md5(did));
    }
}

NB: Classes are not complete, and there are more classes in my project.注意:课程不完整,我的项目中还有更多课程。 I only put what I saw as relevant information.我只把我看到的作为相关信息。 If something else is needed, just ask me please.如果需要其他东西,请问我。 By the way, all the endpoints are defined into a unique @Controller class, and all the endpoints are working except those needing the getTechCookie @Bean.顺便说一句,所有端点都定义为一个唯一的@Controller class,除了需要getTechCookie @Bean 的端点之外,所有端点都在工作。

So, my problem occurs in runtime execution.所以,我的问题发生在运行时执行中。 When I start my Spring Boot app, Jetty is started and listening on the configured port.当我启动我的 Spring Boot 应用程序时,Jetty 启动并侦听配置的端口。 Nevertheless, if you look at the CookieService @Service, I'm listing all the bean names defined in the autowired context and my getTechnicalCookie (aka KngAflow) @Bean is missing.不过,如果您查看 CookieService @Service,我会列出自动装配上下文中定义的所有 bean 名称,而我的 getTechnicalCookie(又名 KngAflow)@Bean 丢失了。 I can't understand why.我不明白为什么。

Of course, when I invoke my @controller to execute my @Service code, the NoSuchBeanDefinitionException is thrown executing the line app.getBean(KngAflow.class).当然,当我调用 @controller 来执行 @Service 代码时,会在执行 app.getBean(KngAflow.class) 行时抛出 NoSuchBeanDefinitionException。

I tried to use a bean name instead of bean type, no change.我尝试使用 bean 名称而不是 bean 类型,没有变化。 For testing purpose (as it doesn't make sense from a logical point of view), I defined my bean getTechCookie @Bean as a Singleton scoped bean, and the name is still missing from the ApplicationContext.出于测试目的(因为从逻辑角度来看它没有意义),我将我的 bean getTechCookie @Bean 定义为 Singleton 范围的 bean,并且 ApplicationContext 中仍然缺少该名称。

And the last but not least thing is: Everything works fine with Eclipse!最后但并非最不重要的是:Eclipse 一切正常!

I mean, all my devs are done using Eclipse IDE.我的意思是,我所有的开发人员都是使用 Eclipse IDE 完成的。 My Spring Boot app is built with Maven and executing it inside Eclipse works correctly (and my getTechCookie Bean is defined and listed).我的 Spring 引导应用程序是用 Maven 构建的,并在 Z32F7222026696F30787889196F30787889194DEE83E5Z 中执行它可以正常工作(并且我的 getTechCookie Bean 已定义并列出)。

When I package my app using the Maven Spring Boot plugin and execute it using java -jar, my getTechCookie (KngAflow.class) bean is missing. When I package my app using the Maven Spring Boot plugin and execute it using java -jar, my getTechCookie (KngAflow.class) bean is missing. Nevertheless, this class is present inside the jar.然而,这个 class 存在于 jar 内部。

Spring parameters to launch the spring boot app are spring default values (port 8080, no SSL, ...) and the active.profiles are always between dev, int, pre or pro (those defined in my @Configuration class) Spring parameters to launch the spring boot app are spring default values (port 8080, no SSL, ...) and the active.profiles are always between dev, int, pre or pro (those defined in my @Configuration class)

What am I doing wrong?我究竟做错了什么?

Thanks!谢谢!

If it helps, I add my POM definition:如果有帮助,我添加我的 POM 定义:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <artifactId>my-app</artifactId>
    <packaging>jar</packaging>

    <parent>
        <groupId>com.mydomain.bigdata</groupId>
        <artifactId>mybigapp</artifactId>
        <version>1.1-SNAPSHOT</version>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jetty</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.kafka</groupId>
            <artifactId>spring-kafka</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>
    </dependencies>

    <build>
        <resources>
            <resource>
                <directory>${basedir}/src/main/resources</directory>
                <filtering>true</filtering>
                <includes>
                    <include>**/*</include>
                    <include>application.yml</include>
                </includes>
            </resource>
        </resources>

        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

EDIT: I changed my @Service class to "force" spring to accept my class as a prototype bean, and it works.编辑:我将我的@Service class 更改为“强制” spring 以接受我的 class 作为原型 bean,并且它可以工作。 It's very ugly but it works.它非常难看,但它有效。 But if someone could help me to find what's wrong, I don't like this workaround:但是,如果有人可以帮助我找出问题所在,我不喜欢这种解决方法:

@Override
    public void afterPropertiesSet() throws Exception {
        if (!context.containsBeanDefinition(KngAflow.class.getName()))
            context.registerBeanDefinition(KngAflow.class.getName(),
                    BeanDefinitionBuilder.genericBeanDefinition(KngAflow.class).setScope("prototype").getBeanDefinition());
    }

I made a following simple application to reproduce issue.我做了一个以下简单的应用程序来重现问题。

@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        run(Application.class, args);
    }

}
@Configuration
@Profile("dev")
public class BeanConfiguration {

    @Bean
    @Scope(scopeName = SCOPE_PROTOTYPE)
    public PrototypeBean prototypeBean() {
        return new PrototypeBean();
    }

}
public class PrototypeBean {}
@Service
@Slf4j
public class SingletonBean implements InitializingBean {

    @Autowired
    private ApplicationContext context;

    public PrototypeBean getPrototypeBean() {
        return context.getBean(PrototypeBean.class);
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        for (String name : context.getBeanDefinitionNames()) {
            Class<?> c = context.getBean(name).getClass();
            log.debug("===> Name: {}, Type = {}", name, c.getTypeName());
        }
    }

}
@RestController
@RequestMapping("/bean")
public class BeanRestController {

    @Autowired
    private SingletonBean singletonBean;

    @GetMapping("/name")
    public String getName() {
        return singletonBean.getPrototypeBean().getClass().getName();
    }

}

When I execute application with -Dspring.profiles.active=dev setting当我使用-Dspring.profiles.active=dev设置执行应用程序时

Then I see in the log without no issue and REST endpoint gives back response properly:然后我在日志中看到没有问题,并且 REST 端点正确返回响应:

===> Name: prototypeBean, Type = PrototypeBean

But if I execute application without profile setting但是如果我在没有配置文件设置的情况下执行应用程序

Then I see error in the log and REST endpoint raise exception:然后我在日志中看到错误,并且 REST 端点引发异常:

org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'PrototypeBean' available

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 为什么我的 Spring Boot 应用程序出现异常? - Why am I getting exception in my Spring Boot Application? 我无法使用 JPA spring 引导通过 email 搜索我的用户 - I am not able to search my users by email using JPA spring boot bean定义未加载到Spring上下文中 - bean definition is not loading into spring context 为什么我无法在 Spring 引导应用程序中使用 @Getter 和 @Setter 注释访问 get 和 set 方法? || 龙目岛 - why I am not able to access the get and set method using @Getter and @Setter Annotation in Spring Boot Application? || Lombok 为什么我的所有Spring启动器执行器端点都是公开的? - Why are all my Spring boot actuator endpoints publicly available? 我为我的 spring 启动应用程序收到在 class 路径资源中定义的名称为 'requestMappingHandlerAdapter' 的创建 bean 时出错 - I get the 'Error creating bean with name 'requestMappingHandlerAdapter' defined in class path resource' for my spring boot application Spring Boot试图解决不在我的xml中的bean - Spring Boot trying to resolve bean not in my xml 我的项目 Spring 创建的 Bean 中的启动问题 - My project Spring Boot problem in created Bean Spring Boot无法从我的文件系统中获取配置文件 - Spring boot is not able to get configuration file from my file system 在 Spring Boot 中工作时,如何在 xml 定义中获取我的应用程序上下文 - How can i get my Application Context in xml defination while working in Spring Boot
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM