首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Spring如何知道在哪里搜索组件或Beans?

Spring如何知道在哪里搜索组件或Beans?
EN

Stack Overflow用户
提问于 2020-06-04 02:52:09
回答 3查看 4.2K关注 0票数 10

在一次采访中,面试官问我“如何知道在哪里搜索组件或Beans?”。

由于我不知道内部流程的细节,所以我无法正确回答这个问题。

我说通过@Component@Bean我们可以找到。但是面试官对这个问题并不满意。如果有人知道,请分享你的知识。提亚

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2020-06-04 03:57:21

我喜欢回答面试问题。看下面..。

代码语言:javascript
复制
@ComponentScan

如果您了解组件扫描,则了解Spring。

Spring是一个依赖注入框架。这一切都是关于bean和依赖关系中的连接。

定义Spring的第一步是添加正确的注释- @Component@Service@Repository

但是,Spring不知道bean的情况,除非它知道在哪里搜索它。

这部分“告诉春天在哪里搜索”被称为组件扫描.

定义必须扫描的包。

一旦为包定义了组件扫描,Spring就会搜索包及其所有子包中的组件/bean。

定义组件扫描

  • 如果您正在使用Spring,请检查方法1中的配置。如果您正在执行JSP/Servlet或Spring应用程序而不使用Spring,则使用方法2.

方法1: Spring项目中的组件扫描

如果您的其他包层次结构在主应用程序下面,并带有@SpringBootApplication注释,那么您将被隐式组件扫描所覆盖。如果其他包中有bean/组件不是主包的子包,则应手动将它们添加为@ComponentScan

考虑下课

代码语言:javascript
复制
package com.in28minutes.springboot.basics.springbootin10steps;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
@SpringBootApplication
public class SpringbootIn10StepsApplication {
    public static void main(String[] args) {
        ApplicationContext applicationContext =
            SpringApplication.run(SpringbootIn10StepsApplication.class, args);
        for (String name: applicationContext.getBeanDefinitionNames()) {
            System.out.println(name);
        }
    }
}

@SpringBootApplication是在包com.in28minutes.springboot.basics.springbootin10steps中的SpringbootIn10StepsApplication类中定义的

@SpringBootApplication定义了包com.in28minutes.springboot.basics.springbootin10steps上的自动组件扫描。

如果您的所有组件都定义在上面的包或它的子包中,那么您就没事了。

但是,假设其中一个组件是在包com.in28minutes.springboot.somethingelse中定义的

在这种情况下,需要将新包添加到组件扫描中。

你有两个选择:

选项1:

代码语言:javascript
复制
@ComponentScan(“com.in28minutes.springboot”)
@SpringBootApplication
public class SpringbootIn10StepsApplication {...}

选项2::定义为数组

代码语言:javascript
复制
@ComponentScan({"com.in28minutes.springboot.basics.springbootin10steps","com.in28minutes.springboot.somethingelse"})
@SpringBootApplication
public class SpringbootIn10StepsApplication {...}

方法2:非Spring启动项目

选项1:

代码语言:javascript
复制
@ComponentScan(“com.in28minutes)
@Configuration
public class SpringConfiguration {...}

备选方案2:

代码语言:javascript
复制
@ComponentScan({"com.in28minutes.package1","com.in28minutes.package2"})
@Configuration
public class SpringConfiguration {...}

XML应用程序上下文:

代码语言:javascript
复制
<context:component-scan base-package="com.in28minutes" />

特定于的多个包:

代码语言:javascript
复制
<context:component-scan base-package="com.in28minutes.package1, com.in28minutes.package2" />
票数 9
EN

Stack Overflow用户

发布于 2020-06-04 04:29:16

IoC (反转控制)容器,用类ApplicationContext表示在Spring中,是这一切背后的大脑。这一切归结为以一种非常强大的方式使用反射。

为了简化,让我们考虑以下步骤(所有步骤都是通过反射完成的):

@Component

  • For
  1. 从这些类中搜索类路径
  2. 中的所有类,将所有类注释为@Component,创建该类的新实例
  3. 检查依赖项,即为每个创建的实例检查带@Autowired注释的所有字段,并为每个字段创建一个实例。

<代码>H 113将所有内容保存在上下文中,以便以后使用。H 214G 215

这个答案的其余部分是一个oversimplified版本,它描述了这一切是如何发生的,就像我们自己做的那样。谢天谢地,春天是存在的,我们不需要自己去做。

注释

代码语言:javascript
复制
@Retention(RetentionPolicy.RUNTIME)
public @interface Node {}

@Retention(RetentionPolicy.RUNTIME)
public @interface Wire { }

一些用于测试的带注释类

代码语言:javascript
复制
@Node
public class ServiceA {
    @Wire
    private ServiceB serviceB;

    public void doAStuff() {
        System.out.println("A stuff");
        serviceB.doBStuff();
    }
}

@Node
public class ServiceB {
    public void doBStuff() {
        System.out.println("B stuff");
    }
}

IoC容器

代码语言:javascript
复制
import org.reflections.Reflections;
/* dependency org.reflections:reflections:0.9.12 */

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class IoC {
    private final Map<Class<?>, Object> allNodes = new HashMap<>();

    public void start() {
        Reflections reflections = new Reflections(IoC.class.getPackageName());
        Set<Class<?>> nodeClasses = reflections.getTypesAnnotatedWith(Node.class);

        try {
            for (Class<?> c : nodeClasses) {
                Object thisInstance = c.getDeclaredConstructor().newInstance();

                for (Field f : c.getDeclaredFields()) {
                    f.setAccessible(true);
                    if (f.getDeclaredAnnotation(Wire.class) != null) {
                        Object o = f.getType().getDeclaredConstructor().newInstance();
                        f.set(thisInstance, f.getType().cast(o));
                    }
                }

                allNodes.put(c, thisInstance);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public <T> T getNodeByType(Class<T> cls) {
        return cls.cast(allNodes.get(cls));
    }
}

主要的课程开始了。

代码语言:javascript
复制
public class Application {
    public static void main(String[] args) {
        IoC ioc = new IoC();
        ioc.start();

        ServiceA serviceA = ioc.getNodeByType(ServiceA.class);
        serviceA.doAStuff();
    }
}

这将产生以下结果:

代码语言:javascript
复制
A stuff
B stuff

当然,Spring比这个更强大(更健壮)。它允许使用@ComponentScan、具有不同名称的相同类型的bean、单例/原型作用域bean、构造函数连接、属性文件注入等多种方式进行自定义包扫描。当涉及Spring时,@SpringBootApplication注释确保它找到并连接所有@Controller注释类,并设置一个Netty/Jetty/Tomcat嵌入式服务器来侦听请求,并根据带注释的类型重定向到适当的控制器。

票数 5
EN

Stack Overflow用户

发布于 2020-06-04 03:07:43

在哪里搜索bean是由@ComponentScan定义的,它可以在用于引导Spring的@Configuration类上进行注释。

例如,它有一个名为scanBasePackages的属性,它告诉Spring扫描bean(一个类被注释为@Component或它的类固醇类型,如@Service@Repository@Controller等)。只从某些包和它的子包。

然后,对于已注册的每个bean,继续查看是否有@Bean.If是的任何方法注释,也可以将它们注册为bean。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/62186071

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档