当前位置:   article > 正文

使用 eclipse搭建sprngboot项目(1 hello world)_eclipse搭建一个简单的springboot项目

eclipse搭建一个简单的springboot项目

 

1 eclipe安装sts插件 

(当前使用的eclipse版本 version=4.7.3
)

  help -> Eclipse Marketplace 

等待插件安装完成,

2 新建项目

next之后,填写项目名称,如果是第一次构建项目,可以按照默认的来,然后看下构建出来的项目结构

然后next ,选择所需的支持,这里只选择web, 由于是通过maven下载的,选得越多,下载时间越长,可以抽个空闲时间,下载

然后选择finish即可 ,等待相关jar包的下载

构建完成的项目结构如下

构建出来的项目有3个文件时比较重要的, 对应上图的箭头指示部分

其中 pom.xml是maven项目做版本管理的,需要什么jar包,直接在里面添加

按照上面步骤构建的项目,内容如下:

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  4. <modelVersion>4.0.0</modelVersion>
  5. <groupId>com.example</groupId>
  6. <artifactId>demo</artifactId>
  7. <version>0.0.1-SNAPSHOT</version>
  8. <packaging>jar</packaging>
  9. <name>demo</name>
  10. <description>Demo project for Spring Boot</description>
  11. <parent>
  12. <groupId>org.springframework.boot</groupId>
  13. <artifactId>spring-boot-starter-parent</artifactId>
  14. <version>2.0.6.RELEASE</version>
  15. <relativePath/> <!-- lookup parent from repository -->
  16. </parent>
  17. <properties>
  18. <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  19. <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
  20. <java.version>1.8</java.version>
  21. </properties>
  22. <dependencies>
  23. <dependency>
  24. <groupId>org.springframework.boot</groupId>
  25. <artifactId>spring-boot-starter-web</artifactId>
  26. </dependency>
  27. <dependency>
  28. <groupId>org.springframework.boot</groupId>
  29. <artifactId>spring-boot-starter-test</artifactId>
  30. <scope>test</scope>
  31. </dependency>
  32. </dependencies>
  33. <build>
  34. <plugins>
  35. <plugin>
  36. <groupId>org.springframework.boot</groupId>
  37. <artifactId>spring-boot-maven-plugin</artifactId>
  38. </plugin>
  39. </plugins>
  40. </build>
  41. </project>

application.properties 是springboot 默认的配置文件地址,可以将配置文件写到里面去 ,默认为空

DemoApplication.java 是程序的入口,名称生成的策略就是 项目名+Application ,项目名就是你在构建项目时填写的;这个类是最重要的,

默认内容如下

  1. package com.example.demo;
  2. import org.springframework.boot.SpringApplication;
  3. import org.springframework.boot.autoconfigure.SpringBootApplication;
  4. @SpringBootApplication
  5. public class DemoApplication {
  6. public static void main(String[] args) {
  7. SpringApplication.run(DemoApplication.class, args);
  8. }
  9. }

3 启动解析

3.1注解

首先来看下这个启动类,只有一个注解,一个main方法,

首先里看这个注解 @SpringBootApplication, 直接查看其源码, 由于是maven项目,会自动下载源码,这个很方便

  1. @Target(ElementType.TYPE)
  2. @Retention(RetentionPolicy.RUNTIME)
  3. @Documented
  4. @Inherited
  5. @SpringBootConfiguration
  6. @EnableAutoConfiguration
  7. @ComponentScan(excludeFilters = {
  8. @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
  9. @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
  10. public @interface SpringBootApplication {
  11. ...
  12. }

可以看到这个注解被其它几个注解所修饰,相当于是 springboot使用这个注解,达到同时使用其它几个注解

其中,上面4个注解,是java.lang.annotation 包下的,是所有注解都要有的

详细一点的说明(均来自java API)

public @interface Documented

指示某一类型的注释将通过 javadoc 和类似的默认工具进行文档化。应使用此类型来注释这些类型的声明:其注释会影响由其客户端注释的元素的使用。如果类型声明是用 Documented 来注释的,则其注释将成为注释元素的公共 API 的一部分。

public @interface Inherited

指示注释类型被自动继承。如果在注释类型声明中存在 Inherited 元注释,并且用户在某一类声明中查询该注释类型,同时该类声明中没有此类型的注释,则将在该类的超类中自动查询该注释类型。此过程会重复进行,直到找到此类型的注释或到达了该类层次结构的顶层 (Object) 为止。如果没有超类具有该类型的注释,则查询将指示当前类没有这样的注释。

注意,如果使用注释类型注释类以外的任何事物,此元注释类型都是无效的。还要注意,此元注释仅促成从超类继承注释;对已实现接口的注释无效。

public @interface Retention

指示注释类型的注释要保留多久。如果注释类型声明中不存在 Retention 注释,则保留策略默认为 RetentionPolicy.CLASS。

只有元注释类型直接用于注释时,Target 元注释才有效。如果元注释类型用作另一种注释类型的成员,则无效。

public @interface Target

指示注释类型所适用的程序元素的种类。如果注释类型声明中不存在 Target 元注释,则声明的类型可以用在任一程序元素上。如果存在这样的元注释,则编译器强制实施指定的使用限制。 例如,此元注释指示该声明类型是其自身,即元注释类型。它只能用在注释类型声明上:

  1. @Target(ElementType.ANNOTATION_TYPE)
  2. public @interface MetaAnnotationType {
  3. ...
  4. }

 下面的3个注释

@SpringBootConfiguration 源码

  1. @Target(ElementType.TYPE)
  2. @Retention(RetentionPolicy.RUNTIME)
  3. @Documented
  4. @Configuration
  5. public @interface SpringBootConfiguration {
  6. }

其实就相当于和 @configuratiion的功能一样,使用该注解之后,可以将这个类看做是 一个配置文件

例如

  1. @Configuration
  2. public class MyConfig {
  3. @Bean
  4. public MyService getUserService(){
  5. UserService userService = new UserService();
  6. userService.setUserDAO(null);
  7. return userService;
  8. }
  9. @Bean
  10. public MyDAO getUserDAO(){
  11. return new UserDAO();
  12. }
  13. }

等价于xml的配置 ,

  1. <beans>
  2. <bean id = "MyService" class="com.shj.MyService">
  3. <property name="userDAO" ref = "userDAO"></property>
  4. </bean>
  5. <bean id = "MyDAO" class="com.shj.MyDAO"></bean>
  6. </beans>

@ComponentScan

相当于配置自动扫描 

等价于spring的配置文件中的

<context:component-scan>

@EnableAutoConfiguration 

  1. @Target(ElementType.TYPE)
  2. @Retention(RetentionPolicy.RUNTIME)
  3. @Documented
  4. @Inherited
  5. @AutoConfigurationPackage
  6. @Import(AutoConfigurationImportSelector.class)
  7. public @interface EnableAutoConfiguration {
  8. String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
  9. /**
  10. * Exclude specific auto-configuration classes such that they will never be applied.
  11. * @return the classes to exclude
  12. */
  13. Class<?>[] exclude() default {};
  14. /**
  15. * Exclude specific auto-configuration class names such that they will never be
  16. * applied.
  17. * @return the class names to exclude
  18. * @since 1.3.0
  19. */
  20. String[] excludeName() default {};
  21. }

查看文档中的文档说明,可以发现 这个注解的作用是  允许spring程序上下文的自动配置

可以帮助SpringBoot应用将所有符合条件的@Configuration配置都加载到当前SpringBoot创建并使用的IoC容器。

3.2 类解析

  1. public static void main(String[] args) {
  2. SpringApplication.run(DemoApplication.class, args);
  3. }

 查看run()

  1. public static ConfigurableApplicationContext run(Class<?> primarySource,
  2. String... args) {
  3. return run(new Class<?>[] { primarySource }, args);
  4. }

再查看返回时调用的run()

  1. public static ConfigurableApplicationContext run(Class<?>[] primarySources,
  2. String[] args) {
  3. return new SpringApplication(primarySources).run(args);
  4. }

可以看到, 首先实例化了一个SpringApplication ,然后运行run()

首先来查看实例化的过程

  1. public SpringApplication(Class<?>... primarySources) {
  2. this(null, primarySources);
  3. }

真正调用的是这个

  1. @SuppressWarnings({ "unchecked", "rawtypes" })
  2. public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
  3. this.resourceLoader = resourceLoader;
  4. Assert.notNull(primarySources, "PrimarySources must not be null");
  5. this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
  6. this.webApplicationType = WebApplicationType.deduceFromClasspath();
  7. setInitializers((Collection) getSpringFactoriesInstances(
  8. ApplicationContextInitializer.class));
  9. setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
  10. this.mainApplicationClass = deduceMainApplicationClass();
  11. }

一共进行的操作有 :

  判断项目类型

  1.     static WebApplicationType deduceFromClasspath() {
  2.         if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null)
  3.                 && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
  4.                 && !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
  5.             return WebApplicationType.REACTIVE;
  6.         }
  7.         for (String className : SERVLET_INDICATOR_CLASSES) {
  8.             if (!ClassUtils.isPresent(className, null)) {
  9.                 return WebApplicationType.NONE;
  10.             }
  11.         }
  12.         return WebApplicationType.SERVLET;
  13.     }

其中, 常量的定义

  1. private static final String[] SERVLET_INDICATOR_CLASSES = { "javax.servlet.Servlet",
  2. "org.springframework.web.context.ConfigurableWebApplicationContext" };
  3. private static final String WEBMVC_INDICATOR_CLASS = "org.springframework."
  4. + "web.servlet.DispatcherServlet";
  5. private static final String WEBFLUX_INDICATOR_CLASS = "org."
  6. + "springframework.web.reactive.DispatcherHandler";
  7. private static final String JERSEY_INDICATOR_CLASS = "org.glassfish.jersey.servlet.ServletContainer";
  8. private static final String SERVLET_APPLICATION_CONTEXT_CLASS = "org.springframework.web.context.WebApplicationContext";
  9. private static final String REACTIVE_APPLICATION_CONTEXT_CLASS = "org.springframework.boot.web.reactive.context.ReactiveWebApplicationContext";

可能会出现三种结果:

1   WebApplicationType.REACTIVE - 当类路径中存在REACTIVE_WEB_ENVIRONMENT_CLASS并且不存在MVC_WEB_ENVIRONMENT_CLASS时
2  WebApplicationType.NONE - 也就是非Web型应用(Standard型),此时类路径中不包含WEB_ENVIRONMENT_CLASSES中定义的任何一个类时
3   WebApplicationType.SERVLET - 类路径中包含了WEB_ENVIRONMENT_CLASSES中定义的所有类型时
 

设置初始化器(Initializer)

  1. setInitializers((Collection) getSpringFactoriesInstances(
  2. ApplicationContextInitializer.class));

查看代码 

  1. private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
  2. return getSpringFactoriesInstances(type, new Class<?>[] {});
  3. }
  1. private <T> Collection<T> getSpringFactoriesInstances(Class<T> type,
  2. Class<?>[] parameterTypes, Object... args) {
  3. ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
  4. // Use names and ensure unique to protect against duplicates
  5. //避免重复的元素
  6. Set<String> names = new LinkedHashSet<>(
  7. SpringFactoriesLoader.loadFactoryNames(type, classLoader));
  8. //根据names进行实例化
  9. List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
  10. classLoader, args, names);
  11. //排序实例化后的对象
  12. AnnotationAwareOrderComparator.sort(instances);
  13. return instances;
  14. }
  1. //根据完全限定名加载
  2. public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
  3. String factoryClassName = factoryClass.getName();
  4. return loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
  5. }

  1. private <T> List<T> createSpringFactoriesInstances(Class<T> type,
  2. Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args,
  3. Set<String> names) {
  4. List<T> instances = new ArrayList<>(names.size());
  5. for (String name : names) {
  6. try {
  7. Class<?> instanceClass = ClassUtils.forName(name, classLoader);
  8. Assert.isAssignable(type, instanceClass);
  9. Constructor<?> constructor = instanceClass
  10. .getDeclaredConstructor(parameterTypes);
  11. T instance = (T) BeanUtils.instantiateClass(constructor, args);
  12. instances.add(instance);
  13. }
  14. catch (Throwable ex) {
  15. throw new IllegalArgumentException(
  16. "Cannot instantiate " + type + " : " + name, ex);
  17. }
  18. }
  19. return instances;
  20. }

  1. public void setInitializers(
  2. Collection<? extends ApplicationContextInitializer<?>> initializers) {
  3. this.initializers = new ArrayList<>();
  4. this.initializers.addAll(initializers);
  5. }

项目启动很快,然后会发现没什么要显示的,可以做个简单的网页 输出点内容

  1. package com.example.demo.web;
  2. import org.springframework.web.bind.annotation.RequestMapping;
  3. import org.springframework.web.bind.annotation.RestController;
  4. @RestController
  5. public class HelloController {
  6. @RequestMapping("/hello")
  7. public String index() {
  8. return "hello boot";
  9. }
  10. }

重启项目,然后访问:  http://127.0.0.1:8080/hello

有的小伙伴代码写得一样, 会访问不到, 

这个的原因就是: 目录结构不对

这个很重要 ,可以参考官方推荐的项目结构:

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/煮酒与君饮/article/detail/995888
推荐阅读
相关标签
  

闽ICP备14008679号