springboot快速入門及@SpringBootApplication注解分析

Spring boot簡介

  • Spring Boot是伴隨著Spring4.0 產(chǎn)生的,是由Pivotal團隊提供的全新框架,其設(shè)計目的是用來簡化新Spring應用的初始搭建以及開發(fā)過程。該框架使用了特定的方式進行配置,從而使開發(fā)人員不再需要定義樣板化的配置。通過這種方式,Boot致力于在蓬勃發(fā)展的快速應用開發(fā)領(lǐng)域(rapid application development)成為領(lǐng)導者。
  • Spring Boot讓我們的Spring應用變得更輕量化。比如:你可以僅僅依靠一個Java類來運行Spring引用。你也可以打包你的應用為jar并通過使用java –jar來運行你的Spring Web應用。
  • Spring Boot的主要優(yōu)點:
    為所有Spring開發(fā)者更快的入門
    開箱即用,提供各種默認配置來簡化項目配置
    內(nèi)嵌式容器簡化web項目
    沒有冗余代碼生成和xml配置的要求
    盡可能的根據(jù)項目依賴來自動配置Spring框架。
    提供可以直接在生產(chǎn)環(huán)境中使用的功能,如性能指標,應用信息和應用健康檢查。
  • Spring Boot的缺點
    依賴太多,隨便的一個Spring Boot應用都有好幾十M
    缺少服務(wù)的注冊和發(fā)現(xiàn)等解決方案,可以結(jié)合springcloud的組件使用。
    缺少監(jiān)控集成方案、安全管理方案(有但簡單,滿足不了生產(chǎn)的指標)

簡單demo
使用maven構(gòu)建項目,官方現(xiàn)在穩(wěn)定版本是1.5.4,第一個入門demo不是web項目,pom依賴如下:

 <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.4.RELEASE</version>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
    </dependencies>

實體User類:

package com.zhihao.miao.bean;

import org.springframework.stereotype.Component;

@Component
public class User {

   private String username = "zhihao.miao";

   private int age;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "User{" +
                "username='" + username + '\'' +
                ", age=" + age +
                '}';
    }
}

配置類:

package com.zhihao.miao.bean;

import org.springframework.boot.SpringBootConfiguration;
import org.springframework.context.annotation.Bean;

import java.util.HashMap;
import java.util.Map;

@SpringBootConfiguration
public class ConfigurationTest {

    @Bean
    public Map createMap(){
        Map map = new HashMap();
        map.put("username","zhihao.miao");
        map.put("age",27);
        return map;
    }
}

入口類Application

package com.zhihao.miao;

import com.zhihao.miao.bean.User;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;

import java.util.Map;

@SpringBootApplication
public class Application {

    @Bean
    public Runnable createRunnable(){
        return () -> System.out.println("spring boot is running");
    }

    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(Application.class,args);
        context.getBean(Runnable.class).run();
        System.out.println(context.getBean(User.class));
        Map map = (Map) context.getBean("createMap");
        int age = (int) map.get("age");
        System.out.println("age=="+age);

    }
}

項目結(jié)構(gòu)目錄

項目結(jié)構(gòu)目錄

啟動程序,以main方法啟動:

打印出正確的結(jié)果。

spring boot is running
User{username='zhihao.miao', age=0}
age==27

來分析一下流程,為何Runnable類,User,Map會納入spring容器。

首先我們分析的就是入口類Application的啟動注解@SpringBootApplication,進入源碼:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
        @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
        @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
....

發(fā)現(xiàn)@SpringBootApplication是一個復合注解,包括@ComponentScan,和@SpringBootConfiguration@EnableAutoConfiguration

  • @SpringBootConfiguration繼承自@Configuration,二者功能也一致,標注當前類是配置類,并會將當前類內(nèi)聲明的一個或多個以@Bean注解標記的方法的實例納入到srping容器中,并且實例名就是方法名。
  • @EnableAutoConfiguration的作用啟動自動的配置,@EnableAutoConfiguration注解的意思就是Springboot根據(jù)你添加的jar包來配置你項目的默認配置,比如根據(jù)spring-boot-starter-web ,來判斷你的項目是否需要添加了webmvctomcat,就會自動的幫你配置web項目中所需要的默認配置。在下面博客會具體分析這個注解,快速入門的demo實際沒有用到該注解。
  • @ComponentScan,掃描當前包及其子包下被@Component,@Controller@Service,@Repository注解標記的類并納入到spring容器中進行管理。是以前的<context:component-scan>(以前使用在xml中使用的標簽,用來掃描包配置的平行支持)。所以本demo中的User為何會被spring容器管理。

根據(jù)上面的理解,上面的入口類Application,我們可以使用:

package com.zhihao.miao;
import com.zhihao.miao.bean.User;
import org.springframework.boot.SpringApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import java.util.Map;

@ComponentScan
public class Application {

    @Bean
    public Runnable createRunnable(){
        return () -> System.out.println("spring boot is running");
    }

    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(Application.class,args);
        context.getBean(Runnable.class).run();
        System.out.println(context.getBean(User.class));
        Map map = (Map) context.getBean("createMap");
        int age = (int) map.get("age");
        System.out.println("age=="+age);

    }
}

使用@ComponentScan注解代替@SpringBootApplication注解,也可以正常運行程序。原因是@SpringBootApplication中包含@ComponentScan,并且springboot會將入口類看作是一個@SpringBootConfiguration標記的配置類,所以定義在入口類Application中的Runnable也可以納入到容器管理。

SpringBootApplication參數(shù)詳解

圖片.png
  • Class<?>[] exclude() default {}:
    根據(jù)class來排除,排除特定的類加入spring容器,傳入?yún)?shù)value類型是class類型。
  • String[] excludeName() default {}:
    根據(jù)class name來排除,排除特定的類加入spring容器,傳入?yún)?shù)value類型是class的全類名字符串數(shù)組。
  • String[] scanBasePackages() default {}:
    指定掃描包,參數(shù)是包名的字符串數(shù)組。
  • Class<?>[] scanBasePackageClasses() default {}:
    掃描特定的包,參數(shù)類似是Class類型數(shù)組。

看一個demo學會使用這些參數(shù)配置
在包下com.zhihao.miao.springboot定義一個啟動應用類(加上@SpringBootApplication注解)

package com.zhihao.miao.springboot;


import com.zhihao.miao.beans.Cat;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        ConfigurableApplicationContext context =SpringApplication.run(Application.class,args);
        Cat cat = context.getBean(Cat.class);
        System.out.println(cat);
    }
}

在com.zhihao.miao.beans包下定義一個實體類,并且想將其納入到spring容器中,

public class Cat {
}
package com.zhihao.miao.beans;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MyConfig {

    @Bean
    public Cat cat(){
        return new Cat();
    }

}

啟動啟動類,打印結(jié)果如下:

說明Cat類并沒有納入到spring容器中,這個結(jié)果也如我們所想,因為@SpringBootApplication只會掃描@SpringBootApplication注解標記類包下及其子包的類(特定注解標記,比如說@Controller,@Service,@Component,@Configuration和@Bean注解等等)納入到spring容器,很顯然MyConfig不在@SpringBootApplication注解標記類相同包下及其子包的類,所以需要我們?nèi)ヅ渲靡幌聮甙窂健?/p>

修改啟動類,@SpringBootApplication(scanBasePackages = "com.zhihao.miao"),指定掃描路徑:

package com.zhihao.miao.springboot;

import com.zhihao.miao.beans.Cat;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

@SpringBootApplication(scanBasePackages = "com.zhihao.miao")
public class Application {

    public static void main(String[] args) {
        ConfigurableApplicationContext context =SpringApplication.run(Application.class,args);
        Cat cat = context.getBean(Cat.class);
        System.out.println(cat);
    }
}

啟動并打?。?/p>

當然使用@SpringBootApplication(scanBasePackageClasses = MyConfig.class),指定scanBasePackageClasses參數(shù)的value值是你需要掃描的類也可以,結(jié)果一樣,不過如果多個配置類不在當前包及其子包下,則需要指定多個。

再看一個列子,
在上面的列子的相同包下(com.zhihao.miao.springboot)配置了People,并將其納入到spring容器中(@Component),我們知道@SpringBootApplication注解會掃描當前包及其子包,所以People類會納入到spring容器中去,我們需要將其排除在spring容器中,如何操作?
可以使用@SpringBootApplication的另外二個參數(shù)(exclude或excludeName)

package com.zhihao.miao.springboot;

import org.springframework.stereotype.Component;

@Component
public class People {
}

啟動類,

package com.zhihao.miao.springboot;


import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        ConfigurableApplicationContext context =SpringApplication.run(Application.class,args);
        People people = context.getBean(People.class);
        System.out.println(people);
    }
}

啟動并打印結(jié)果:

然后修改@SpringBootApplication配置,

package com.zhihao.miao.springboot;


import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

@SpringBootApplication(exclude = People.class)
public class Application {

    public static void main(String[] args) {
        ConfigurableApplicationContext context =SpringApplication.run(Application.class,args);
        People people = context.getBean(People.class);
        System.out.println(people);
    }
}

很明顯啟動報錯。使用@excludeName注解也可以。如下,
@SpringBootApplication(excludeName = {"com.zhihao.miao.springboot.People"})

參考文檔:
Springboot1.5.4官方文檔

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容