SpringBoot-day1

1.Spring核心

Spring兩大核心:基于工廠模式IOC(DI)和基于動態(tài)代理AOP。

  1. IOC(DI)是指控制器反轉(zhuǎn)(依賴注入)诸迟,原來要使用某個類對象實例是必須自己創(chuàng)建茸炒,使用spring后就不需要自己創(chuàng)建愕乎,由spring控制,需要時直接從spring中獲取并且有依賴關(guān)系是會spring會通過反射自動注入壁公。
  2. AOP就是不影響這場執(zhí)行過程的前后加入額外的邏輯感论。比如權(quán)限,日志等紊册,該執(zhí)行的業(yè)務(wù)邏輯正常執(zhí)行知識可以進行權(quán)限的判斷核日志記錄笛粘。

2.Spring注解編程-IOC

2.1 引入

以前是通過配置文件的方式注冊bean,其實現(xiàn)在spring提倡以注解驅(qū)動的方式實現(xiàn)bean的注冊

2.2 環(huán)境準(zhǔn)備

  1. 創(chuàng)建一個maven項目
  2. 導(dǎo)包湿硝。在pom.xml中粘貼
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>4.3.12.RELEASE</version>
</dependency>

2.3 傳統(tǒng)方式獲取bean

  1. 在main下的resources下創(chuàng)建xml文件.我這里取名beans.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd
      ">

    <bean id="myDate" class="java.util.Date"></bean>

</beans>
  1. 測試。這里會打印出時間润努,測試成功关斜!
package cn.wangningbo;

import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class IOCTest {
    /**
     * 傳統(tǒng)方式
     * @throws Exception
     */
    @Test
    public void test() throws Exception {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        Object myDate = context.getBean("myDate");
        System.out.println(myDate);
    }
}

2.4 Bean注冊

2.4.1 配置類和Bean注解

  1. @Configuration:加了這個注解的類就是配置類,相當(dāng)于傳統(tǒng)的一個applicationContext-xxx.xml
  2. @Bean:在標(biāo)注了@Configuration的類里面的方法上面打上@bean就是注冊了這個Bean铺浇,相當(dāng)于在applicationContext-xxx.xml配置的一個<bean id=”userDao” class=”cn.itsource.dao.UserDao”>

注意:bean的名字默認(rèn)就是方法名痢畜,如果想改方法名使用@Bean(“beanName”)

2.4.1.1 配置類&Bean Bean名字

配置類:在類上面打上@Configuration注解
注冊Bean:在配置類里面的方法上打上@Bean注解
Bean名字:@Bean注解有個參數(shù)name,賦值就可以了

package cn.wangningbo.config;

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

import java.util.Date;

@Configuration//注解類==配置文件 //告訴spring這是一個注解類 //這個注解的類就相當(dāng)于傳統(tǒng)的一個applicationContext-xxx.xml
public class MainConfig {
    //    @Bean(name = "nameTest")//自定義了名字就使用自定義的名字
    @Bean//未自定義名字就會默認(rèn)是方法名
    public Date myDate() {
        return new Date();
    }
}

測試方法

    /**
     * 注解方式
     * @throws Exception
     */
    @Test
    public void testAnnotationIoc() throws Exception {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig.class);
        Object myDate = context.getBean("myDate");//未自定義名字就會默認(rèn)是方法名
//        Object myDate = context.getBean("nameTest");//自定義了名字就使用自定義的名字
        System.out.println(myDate);
    }

2.4.1.2 配置類&Bean&@Scope 單例模式或多例模式

@Scope:用來配置這個類是單例模式還是多例模式鳍侣,如果不配置丁稀,默認(rèn)就是單例模式

單例模式(singleton):單例類只能有一個實例。
多例模式(prototype):每次獲取都是新的實例倚聚。

使用方法:@Scope注解有個value參數(shù)线衫,賦值就可以了

package cn.wangningbo.config;

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

import java.util.Date;

@Configuration//注解類==配置文件 //告訴spring這是一個注解類 //這個注解的類就相當(dāng)于傳統(tǒng)的一個applicationContext-xxx.xml
public class MainConfig {

    @Bean//未自定義名字就會默認(rèn)是方法名
    @Scope(value = "prototype") //默認(rèn)是singleton(單例模式),可以配置為prototype(多例模式)
    public Date myDate() {
        return new Date();
    }
}

測試

    /**
     * 測試單例模式和多例模式
     *
     * @throws Exception
     */
    @Test
    public void testScope() throws Exception {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig.class);
        Object myDate = context.getBean("myDate");
        Thread.sleep(2000);
        Object myDate2 = context.getBean("myDate");
        System.out.println(myDate);
        System.out.println(myDate2);
        //單例模式下打印的時間是一樣的
        //多例模式下打印的時間是不一樣的
    }

2.4.1.3 配置類&Bean&@Lazy 懶加載或迫切加載

@Lazy:配置這個類是否使用懶加載。如果不打這個注解惑折,默認(rèn)就是迫切加載授账,打了注解就是懶加載

  1. 創(chuàng)建一個自己的類,提供構(gòu)造方法惨驶,用于測試
package cn.wangningbo.domain;

public class User {
    public User() {
        System.out.println("User create...");
    }
}
  1. 配置類里配置
@Configuration//注解類==配置文件 //告訴spring這是一個注解類 //這個注解的類就相當(dāng)于傳統(tǒng)的一個applicationContext-xxx.xml
public class MainConfig {

    @Bean
    @Lazy//如果不打這個注解白热,默認(rèn)就是迫切加載,打了注解就是懶加載
    public User user() {
        return new User();
    }
}
  1. 測試方法
    /**
     * 懶加載 測試
     *
     * @throws Exception
     */
    @Test
    public void testLazy() throws Exception {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig.class);
        Object user = context.getBean("user");//注釋掉這一行粗卜,沒有執(zhí)行構(gòu)造方法屋确,就是懶加載!反之就是迫切加載
    }

2.4.1.4 配置類&Bean&@Conditional 按照條件注冊

@Conditional:滿足條件的類才會注冊

使用這個注解的類要實現(xiàn)Condition接口才會生效

注意點:@Conditional注解也可以打在類上面

  1. 準(zhǔn)備2個類

LinuxCondition

package cn.wangningbo.condition;

import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotatedTypeMetadata;

public class LinuxCondition implements Condition {
    /**
     * @param conditionContext      條件上下文续扔,可以獲取一些信息攻臀,來判斷是否條件
     * @param annotatedTypeMetadata 當(dāng)前方法或注解類的注解類型元數(shù)據(jù)信息
     * @return
     */
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
        //常用方法
        //1 獲取beanFactory
        ConfigurableListableBeanFactory beanFactory = conditionContext.getBeanFactory();
        //2 獲取類家長群
        ClassLoader classLoader = conditionContext.getClassLoader();
        //3 獲取當(dāng)前運行環(huán)境
        Environment environment = conditionContext.getEnvironment();
        //4 獲取bean的注冊器,獲取手動注冊bean到spring容器
        BeanDefinitionRegistry registry = conditionContext.getRegistry();
        // 5. 獲取當(dāng)前運行環(huán)境的名字
        String osName = environment.getProperty("os.name");
        if (osName.contains("Linux")) {
            return true;
        }
        return false;
    }
}

WindowsCondition

package cn.wangningbo.condition;

import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotatedTypeMetadata;

public class WindowsCondition implements Condition {
    /**
     * @param conditionContext      條件上下文纱昧,可以獲取一些信息茵烈,來判斷是否條件
     * @param annotatedTypeMetadata 當(dāng)前方法或注解類的注解類型元數(shù)據(jù)信息
     * @return
     */
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
        //常用方法
        //1 獲取beanFactory
        ConfigurableListableBeanFactory beanFactory = conditionContext.getBeanFactory();
        //2 獲取類家長群
        ClassLoader classLoader = conditionContext.getClassLoader();
        //3 獲取當(dāng)前運行環(huán)境
        Environment environment = conditionContext.getEnvironment();
        //4 獲取bean的注冊器,獲取手動注冊bean到spring容器
        BeanDefinitionRegistry registry = conditionContext.getRegistry();
        // 5. 獲取當(dāng)前運行環(huán)境的名字
        String osName = environment.getProperty("os.name");
        if (osName.contains("Windows")) {
            return true;
        }
        return false;
    }
}
  1. 配置類
@Configuration//注解類==配置文件 //告訴spring這是一個注解類 //這個注解的類就相當(dāng)于傳統(tǒng)的一個applicationContext-xxx.xml
public class MainConfig {

    @Bean
    @Conditional(value = LinuxCondition.class)//根據(jù)這個條件決定是否注冊
    public User userLinux() {
        System.out.println("Linux條件成立");
        return new User();
    }

    @Bean
    @Conditional(value = WindowsCondition.class)//根據(jù)這個條件決定是否注冊
    public User userWindows() {
        System.out.println("Windows條件成立");
        return new User();
    }
}
  1. 測試
/**
     * 條件注冊 測試
     *
     * @throws Exception
     */
    @Test
    public void testConditional() throws Exception {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig.class);
        //輸出了配置類里面的輸出語句砌些,就注冊了那個Bean
    }

2.4.2 @ComponentScan掃描bean

??我們原來使用spring的使用不會在xml中一個一個配置bean呜投,我們在再類上加上@Repository加匈,@Service,@Controller @Component,并且注入時可以使用@AutoWired的注解注入。 這一切的功能都需要我們配置包掃描<context:component-scan base-package="cn.wangningbo"/>.

??然而現(xiàn)在注解驅(qū)動開發(fā)已經(jīng)沒有了配置文件仑荐,不能配置雕拼。但是提供了@ComponentScan,我們可以在配置類上面加上這個注解也是一樣粘招,并且也能掃描配置包項目的相關(guān)注解啥寇,也能完成自動注入。

??@ComponentScan的效果和以前在xml中配置<context:component-scan base-package="cn.wangningbo"/>. 效果是一樣的

2.4.2.1 基本語法(掃描單個包)

在配置類上面打注解@ComponentScan(value = "包路徑")

  1. 配置類
package cn.wangningbo.config;

import cn.wangningbo.dao.UserDao;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration//注解類==配置文件 //告訴spring這是一個注解類 //這個注解的類就相當(dāng)于傳統(tǒng)的一個applicationContext-xxx.xml
@ComponentScan(value = "cn.wangningbo") //掃描單個包
public class MainConfig2 {

    //不變還使用Bean方式
    @Bean
    public UserDao userDao() {
        return new UserDao();
    }
}
  1. dao
package cn.wangningbo.dao;

public class UserDao {
    public void addUser() {
        System.out.println("add user ....");
    }
}
  1. service
package cn.wangningbo.service;

import cn.wangningbo.dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserService {

    @Autowired
    private UserDao userdao;

    public void addUser() {
        userdao.addUser();
    }
}
  1. controller
package cn.wangningbo.controller;

import cn.wangningbo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

@Controller
public class UserController {
    @Autowired
    private UserService service;

    public void addUser() {
        service.addUser();
    }
}
  1. 測試
    /**
     * ComponentScan 掃描包 測試
     *
     * @throws Exception
     */
    @Test
    public void testComponentScan() throws Exception {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig2.class);
        //向獲取spring中所有的bean的類型
        for (String beanName : context.getBeanDefinitionNames()) {
            System.out.println(beanName);
        }
    }

2.4.2.2 高級語法(掃描多個包)

2.4.2.2.1 掃描多個包的方式一:配置多個@ComponentScan

配置類中使用多個注解@ComponentScan(value = "包路徑")

package cn.wangningbo.config;

import cn.wangningbo.dao.UserDao;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration//注解類==配置文件 //告訴spring這是一個注解類 //這個注解的類就相當(dāng)于傳統(tǒng)的一個applicationContext-xxx.xml
@ComponentScan(value = "cn.wangningbo.service") //掃描dao
@ComponentScan(value = "cn.wangningbo.controller") //掃描service
public class MainConfig3 {

    //不變還使用Bean方式
    @Bean
    public UserDao userDao() {
        return new UserDao();
    }
}
2.4.2.2.2 掃描多個包的方式二:使用@ComponentScans

在配置類上面使用ComponentScans注解,value里面可以寫多個@ComponentScan
@ComponentScans(value = {
??@ComponentScan("cn.wangningbo.service"),
??@ComponentScan("cn.wangningbo.controller")
})

配置類

package cn.wangningbo.config;

import cn.wangningbo.dao.UserDao;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScans;
import org.springframework.context.annotation.Configuration;

@Configuration//注解類==配置文件 //告訴spring這是一個注解類 //這個注解的類就相當(dāng)于傳統(tǒng)的一個applicationContext-xxx.xml
@ComponentScans(value = {  //在配置注解時{表示配置多個
        @ComponentScan("cn.wangningbo.service"),
        @ComponentScan("cn.wangningbo.controller")
})
public class MainConfig3 {

    //不變還使用Bean方式
    @Bean
    public UserDao userDao() {
        return new UserDao();
    }
}
2.4.2.2.3 包含和過濾

注意:如果使用同時包含和排除同一個注解要在兩個配置類中

// useDefaultFilters = false //包含要生效,必須去除默認(rèn)過濾器

配置類

package cn.wangningbo.config;

import cn.wangningbo.dao.UserDao;
import org.springframework.context.annotation.*;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Service;

@Configuration//注解類==配置文件 //告訴spring這是一個注解類 //這個注解的類就相當(dāng)于傳統(tǒng)的一個applicationContext-xxx.xml
@ComponentScans(value = {
        @ComponentScan(
                value = "cn.wangningbo",
                excludeFilters = {  // 排除
                        @ComponentScan.Filter(type = FilterType.ANNOTATION,
                                classes = {Controller.class})
                }
//                includeFilters = { // 包含
//                        @ComponentScan.Filter(type = FilterType.ANNOTATION,
//                                classes = {Service.class})
//                },
//                useDefaultFilters = false //包含要生效,必須去除默認(rèn)過濾器
        )
})
public class MainConfig4 {

    //不變還使用Bean方式
    @Bean
    public UserDao userDao() {
        return new UserDao();
    }
}

2.4.3 @Import

@Import(快速向容器中注冊一個bean)

  • (1)@Import(要導(dǎo)入的組件)洒扎,名稱就是類的全限定名
  • (2)ImportSelector:導(dǎo)入選擇器辑甜,返回需要導(dǎo)入組件類的全限定名數(shù)組-springboot底層用的多
  • (3)ImportBeanDefinitionRegistrar:通過bean定義注冊器手動項目spring中容器中注冊
  1. 配置類
package cn.wangningbo.importTest;

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

@Configuration  //告訴Spring這是一個配置類
@Import(value = {RedColor.class, GreenColor.class, MyImportSelector.class, MyImportBeanDefinitionRegistrar.class})
public class MainConfig5 {

    /** @Import(快速向容器中注冊一個bean)
     *      1)@Import(要導(dǎo)入的組件),名稱就是累的全限定名
     *      2)ImportSelector:導(dǎo)入選擇器袍冷,返回需要導(dǎo)入組件類的全限定名數(shù)組-springboot底層用的多
     *      3)ImportBeanDefinitionRegistrar:通過bean定義注冊器手動項目spring中容器中注冊
     */
}
  1. 準(zhǔn)備測試所需要的普通類
package cn.wangningbo.importTest;

public class RedColor {
}
package cn.wangningbo.importTest;

public class GreenColor {
}
package cn.wangningbo.importTest;

public class PinkColor {
}
package cn.wangningbo.importTest;

public class YellowColor {
}
package cn.wangningbo.importTest;

import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;

public class MyImportSelector implements ImportSelector {
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        System.out.println(annotationMetadata.getClassName());
        //把滿足條件的類們的全限定名以數(shù)組方式進行返回
        return new String[]{"cn.wangningbo.importTest.PinkColor", "cn.wangningbo.importTest.YellowColor"};
    }
}
package cn.wangningbo.importTest;

public class XxxColor {
}
package cn.wangningbo.importTest;

import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;

/**
 * 通過bean注冊器直接注冊bean
 */
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
    /**
     * //就是可以在這個方法里面注冊我們bean
     *
     * @param annotationMetadata     元數(shù)據(jù)
     * @param beanDefinitionRegistry Bean定義注冊表
     */
    public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) {
        // 注冊到根容器中
        beanDefinitionRegistry.registerBeanDefinition("XxxColor",
                new RootBeanDefinition(XxxColor.class));
        beanDefinitionRegistry.registerBeanDefinition("XxxColor1",
                new RootBeanDefinition(XxxColor.class));
        beanDefinitionRegistry.registerBeanDefinition("XxxColor2",
                new RootBeanDefinition(XxxColor.class));
        beanDefinitionRegistry.registerBeanDefinition("XxxColor3",
                new RootBeanDefinition(XxxColor.class));
        beanDefinitionRegistry.registerBeanDefinition("XxxColor4",
                new RootBeanDefinition(XxxColor.class));
    }
}
  1. 測試
package cn.wangningbo.importTest;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class ImportTest {
    /**
     * import注冊bean 測試
     *
     * @throws Exception
     */
    @Test
    public void testImport() throws Exception {
        ApplicationContext context = new AnnotationConfigApplicationContext(MainConfig5.class);
        for (String s : context.getBeanDefinitionNames()) {
            System.out.println(s);
        }
    }
}

2.4.4 使用FactoryBean注冊組件

那個類要實現(xiàn)FactoryBean接口

  1. 配置類
package cn.wangningbo.factoryBeanTest;

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

@Configuration
public class MainConfig6 {

    //獲取到的不是UserFactoryBean,而是通過這個factorybean創(chuàng)建對象
    @Bean
    public UserFactoryBean factoryBean(){
        return new UserFactoryBean();
    }
}
  1. 類準(zhǔn)備
package cn.wangningbo.factoryBeanTest;

import cn.wangningbo.domain.User;
import org.springframework.beans.factory.FactoryBean;

public class UserFactoryBean implements FactoryBean<User> {
    public User getObject() throws Exception {
        return new User();
    }

    public Class<?> getObjectType() {
        return User.class;
    }

    public boolean isSingleton() {
        return true;
    }
}
  1. 測試
package cn.wangningbo.factoryBeanTest;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class FactoryBeanTest {
    @Test
    public void testImport() throws Exception {
        ApplicationContext context = new AnnotationConfigApplicationContext(MainConfig6.class);
        System.out.println(context.getBean("factoryBean"));
        //注意:這里雖然是獲取factoryBean磷醋,但實際拿到的是User,詳情看cn.wangningbo.factoryBeanTest.UserFactoryBean
    }
}

2.4.5 總結(jié):注冊Bean的4種方式

  1. @Bean
    • name
    • scope
    • lazy
    • conditional
  2. @ComponentScan/@ComponentScans
    • 一個ComponentScan
      • exclude
      • include
      • useDefaultFilters
    • 多個ComponentScans
      • ComponentScan
  3. @import
    • 類名
    • 選擇器
    • 注冊器
  4. factorybean

2.5 Bean的生命周期

Bean生命周期:創(chuàng)建---->初始化---->銷毀

我們可以自定義bean的初始化和銷毀方法胡诗,并進行指定邓线,bean在容器進行到對應(yīng)生命周期時就會調(diào)用對應(yīng)的方案. xml配置方式 <bean id="userDao" class="cn.itsource.dao.UserDao" init-method="" destroy-method="">

  1. 創(chuàng)建
    單實例bean:在容器創(chuàng)建是就進行指定
    多實例bean:在每次使用時創(chuàng)建
  2. 初始化
    容器創(chuàng)建完成,并賦值好煌恢,完成初始化
  3. 銷毀
    單實例bean:容器關(guān)閉時進行銷毀
    多實例bean:沒有受spring管理骇陈,具體什么時候銷毀有用戶決定。

2.5.1 方式一:@Bean

  1. 配置類
package cn.wangningbo.lifeCycle;

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

@Configuration
public class MainConfig7 {
    @Bean(initMethod = "init", destroyMethod = "destroy")
    @Scope("prototype")   // 單例模式和多例模式分別測試
    public Student student() {
        return new Student();
    }
}
  1. 普通類
package cn.wangningbo.lifeCycle;

public class Student {
    Student() {
        System.out.println("Student create.....");
    }

    public void init() {
        System.out.println("Student init.....");
    }

    public void destroy() {
        System.out.println("Student destroy.....");
    }
}
  1. 測試
package cn.wangningbo.lifeCycle;

import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class LifeCycleTest {
    /**
     * 生命周期 測試
     * 可以看到單例模式下并沒有銷毀 多例模式下每次都會垃圾回收銷毀
     *
     * bean的生命周期: 創(chuàng)建-初始化-銷毀
     * 創(chuàng)建:
     *    單例:IOC容器已啟動就創(chuàng)建(沒有配置Lazy)
     *    多實例:每次使用
     * 初始化:
     *    創(chuàng)建完成就初始化
     * 銷毀:
     *     單例:IOC容器關(guān)閉
     *     多實例:沒有關(guān)系
     * @throws Exception
     */
    @Test
    public void testLifeCycle() throws Exception {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext
                (MainConfig7.class);
        System.out.println("ioc容器創(chuàng)建了!");
        //第一次獲取
        Student p = context.getBean(Student.class);
        System.out.println("使用對象!");
        //關(guān)閉掉
        System.out.println("ioc容器關(guān)閉!");
        context.close();
    }
}

2.5.2 方式二:接口InitializingBean和DisposableBean

那個類要實現(xiàn)InitializingBean, DisposableBean這兩個接口

  1. 配置類
@Configuration
@ComponentScan(value = "cn.wangningbo.lifeCycle")
public class MainConfig7 {

    @Bean
    public Teacher teacher() {
        return new Teacher();
    }
}
  1. 普通類
package cn.wangningbo.lifeCycle;

import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;

public class Teacher implements InitializingBean, DisposableBean {
    // 摧毀的時候調(diào)用
    public void destroy() throws Exception {
        System.out.println("Teacher destroy ...");
    }

    //初始化的時候調(diào)用
    public void afterPropertiesSet() throws Exception {
        System.out.println("Teacher init ...");
    }
}
  1. 測試
    @Test
    public void testLifeCycle() throws Exception {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext
                (MainConfig7.class);
        System.out.println("ioc容器創(chuàng)建了!");
        //第一次獲取
        Teacher teacher = context.getBean(Teacher.class);
        System.out.println("使用對象!");
        //關(guān)閉掉
        System.out.println("ioc容器關(guān)閉!");
        context.close();
    }

2.5.3 方式三:注解@PostConstruct @PreDestroy

在類的某個方法上面加上@PostConstruct瑰抵,創(chuàng)建實例的時候就會執(zhí)行這個方法

在類的某個方法上面加上@PreDestroy你雌,銷毀實例的時候就會執(zhí)行這個方法

  1. 配置類
@Configuration
@ComponentScan(value = "cn.wangningbo.lifeCycle")
public class MainConfig7 {

    @Bean
    public Person person() {
        return new Person();
    }
}
  1. 普通類
package cn.wangningbo.lifeCycle;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

public class Person {
    Person() {
        System.out.println("Person create...");
    }

    @PostConstruct
    public void init() {
        System.out.println("Person init ...");
    }

    @PreDestroy
    public void destroy() {
        System.out.println("Person destroy ...");
    }
}
  1. 測試
    @Test
    public void testLifeCycle() throws Exception {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext
                (MainConfig7.class);
        System.out.println("ioc容器創(chuàng)建了!");
        //第一次獲取
        Person person = context.getBean(Person.class);
        System.out.println("使用對象!");
        //關(guān)閉掉
        System.out.println("ioc容器關(guān)閉!");
        context.close();
    }

2.5.4 方式四:BeanPostProcessor(接口),bean后置處理器

3.SpringBoot簡介

3.1 什么是Spring Boot二汛?

??springBoot是Spring項目中的一個子工程匪蝙,與我們所熟知的Spring-framework 同屬于spring的產(chǎn)品。

??使用springboot习贫,可以讓我們快速的構(gòu)建龐大的spring項目(包括web 持久化)逛球,并且盡可能的減少一切xml配置,做到開箱即用苫昌,迅速上手颤绕,讓我們關(guān)注業(yè)務(wù)而非配置。

3.2 為什么要使用Spring Boot祟身?

它的出現(xiàn)解決了傳統(tǒng)spring項目以下的問題:

  1. 配置負責(zé)繁多
    每一個組件集成spring都需要編寫對應(yīng)配置文件奥务,比如appplicationContext-xxx.xml
  2. 混亂的依賴管理
    在spirng中想集成對應(yīng)組件時,需要導(dǎo)入N多的pom袜硫,并且還有考慮版本氯葬。
    我們使用SpringBoot創(chuàng)建java應(yīng)用,只需填寫很少配置和依賴就能快速搭建婉陷,并使用java –jar 啟動它帚称,就能得到一個生產(chǎn)級別的web工程官研。非常方便

3.3 Spring Boot的特點

  1. 為所有 Spring 的開發(fā)者提供一個非常快速的闯睹、廣泛接受的入門體驗
  2. 開箱即用(啟動器starter-其實就是SpringBoot提供的一個jar包)戏羽,但通過自己設(shè)置參數(shù)(.properties),即可快速擺脫這種方式楼吃。
  3. 提供了一些大型項目中常見的非功能性特性始花,如內(nèi)嵌服務(wù)器、安全孩锡、指標(biāo)酷宵,健康檢測、外部化配置等
  4. 絕對沒有代碼生成躬窜,也無需 XML 配置浇垦。

用過的都說爽!

4.Spring Boot 入門

4.1 環(huán)境要求

  1. JDK 1.8
  2. Maven
  3. idea

4.2 入門

4.2.1 創(chuàng)建maven項目springboot_parent斩披,在pom.xml配置

 <!--在父模塊中直接管理springboot相關(guān)jar的版本-->
    <dependencyManagement>
        <dependencies>
            <!--springboot版本管理,springboot相關(guān)模塊引入是就不需要制定版本了-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>2.0.5.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

4.2.2 創(chuàng)建子模塊springboot_01_helllo讹俊,在pom.xml中配置

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

4.2.3 子模塊控制jar版本的兩種方式

4.2.3.1 方式一:引用父親(常用于多模塊項目)

在子模塊中配置垦沉。我這里就是選擇了這種!

<!--方式1:在父親中通過   dependencyManagement-->
    <parent>
        <artifactId>springboot_parent</artifactId>
        <groupId>cn.wangningbo</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>

4.2.3.2 方式二:在子模塊pom.xml中設(shè)置spring-boot-starter-parent為父親

在子模塊中配置

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

4.2.4 編碼測試

  1. 新建啟動類
package cn.wangningbo;

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

@SpringBootApplication
public class App {
    public static void main(String[] args) {
        SpringApplication.run(App.class, args);
    }
}
  1. 新建Controller類
package cn.wangningbo.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class HelloController {
    
    @RequestMapping("/hello")
    @ResponseBody
    public String hello() {
        return "hello spring boot";
    }
}
  1. 測試

啟動App類中的main方法即可
打開瀏覽器訪問地址:http://localhost:8080/hello

  1. 注意點
    App中的main方法啟動后仍劈,只會掃描App類所在的包下的子子孫孫的包

4.3 Jar包部署

4.3.1 插件支持

在子模塊的pom.xml中配置厕倍。如果子模塊的pom.xml使用的是第二種直接設(shè)置spring-boot-starter-parent為父親的方式,則不需要下面這個配置贩疙,因為已經(jīng)默認(rèn)配置好了

 <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <!--spirngboot入口類-->
                    <mainClass>cn.wangningbo.App</mainClass>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
                <!--如果依賴父親是spring-boot-starter-parent讹弯,就不需要添加-->
            </plugin>
        </plugins>
    </build>

4.3.2 打包

4.3.2.1 方式一:package

4.3.2.2 方式一:install

點擊idea右側(cè)的Maven Projects-->子模塊-->Lifecycle-->右擊install-->Run 子模塊

4.3.3 運行

在剛才所打jar包所在的目錄那里打開黑窗口

  1. windows下運行:
    運行命令:java -jar xxx.jar
  2. Linux下運行:
    運行命令:nohup java -jar xxx.jar &

4.3.4 測試

運行成功后,打開瀏覽器訪問地址:http://localhost:8080/hello

4.4 使用Spring Initializer快速創(chuàng)建Spring Boot項目

??IDE都支持使用Spring的項目創(chuàng)建向?qū)Э焖賱?chuàng)建一個Spring Boot項目这溅;

??選擇我們需要的模塊组民;向?qū)?lián)網(wǎng)創(chuàng)建Spring Boot項目;

默認(rèn)生成的Spring Boot項目悲靴;

  • 主程序已經(jīng)生成好了臭胜,我們只需要我們自己的邏輯
  • resources文件夾中目錄結(jié)構(gòu)
    • static:保存所有的靜態(tài)資源; js css images癞尚;
    • templates:保存所有的模板頁面耸三;(Spring Boot默認(rèn)jar包使用嵌入式的Tomcat,默認(rèn)不支持JSP頁面)浇揩;可以使用模板引擎(freemarker仪壮、thymeleaf);
    • application.properties:Spring Boot應(yīng)用的配置文件胳徽;可以修改一些默認(rèn)設(shè)置积锅;

5.入門探究

5.1 POM.xml文件

5.1.1 jar版本控制

無論子模塊中使用第一種方式還是第二種方式爽彤,最終都會找到同一個父親:spring-boot-dependencies-2.0.5.RELEASE.pom文件!它來真正管理Spring Boot應(yīng)用里面的所有依賴版本乏沸;Spring Boot的版本仲裁中心淫茵;

以后我們導(dǎo)入依賴默認(rèn)是不需要寫版本;(沒有在dependencies里面管理的依賴自然需要聲明版本號)

子模塊中如果使用下面這個第二種方式控制jar蹬跃,那么它的父親是下面的那種匙瘪!

子模塊中配置jar控制

    <!--第二種:直接設(shè)置spring-boot-starter-parent為父親-->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.5.RELEASE</version>
    </parent>

子模塊第二種方式j(luò)ar控制的父親

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-dependencies</artifactId>
        <version>2.0.5.RELEASE</version>
        <relativePath>../../spring-boot-dependencies</relativePath>
    </parent>

5.1.2 啟動器

Spring Boot將所有的功能場景都抽取出來,做成一個個的starters(啟動器)蝶缀,只需要在項目里面引入這些starter相關(guān)場景的所有依賴都會導(dǎo)入進來丹喻。要用什么功能就導(dǎo)入什么場景的啟動器

spring-boot-starter-xxx:spring-boot場景啟動器;幫我們導(dǎo)入了web模塊正常運行所依賴的組件翁都;

在子模塊的pom.xml中配置的這塊代碼就是web的啟動器

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

5.2 主程序類碍论,主入口類

package cn.wangningbo;

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

/**
 * @SpringBootApplication: 來標(biāo)注一個主程序類,說明這是一個Spring Boot應(yīng)用
 */
@SpringBootApplication
public class App {
    public static void main(String[] args) {
        // Spring應(yīng)用啟動起來
        SpringApplication.run(App.class, args);
    }
}

5.2.1 @SpringBootApplication

SpringBootApplication應(yīng)用標(biāo)注在某個類上說明這個類是SpringBoot的主配置類柄慰,SpringBoot就應(yīng)該運行這個類的main方法來啟動SpringBoot應(yīng)用鳍悠;

點擊@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 {

這里面重點是@SpringBootConfiguration,@EnableAutoConfiguration這兩個注解

  1. @SpringBootConfiguration:Spring Boot的配置類坐搔;
    • 標(biāo)注在某個類上藏研,表示這是一個Spring Boot的配置類;
    • @Configuration:配置類上來標(biāo)注這個注解概行;
      • 配置類 ----- 配置文件蠢挡;配置類也是容器中的一個組件;@Component
  2. @EnableAutoConfiguration:開啟自動配置功能凳忙;

以前我們需要配置的東西业踏,Spring Boot幫我們自動配置;@EnableAutoConfiguration告訴SpringBoot開啟自動配置功能涧卵;這樣自動配置才能生效勤家;

點擊@EnableAutoConfiguration查看源碼后會到這個類里面

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {

這里比較重要理解的@AutoConfigurationPackage和@Import(AutoConfigurationImportSelector.class)

①. @AutoConfigurationPackage:自動配置包

再點擊注解查看源碼,就走到了這個類里面

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage {

}

Spring的底層注解@Import柳恐,給容器中導(dǎo)入一個組件却紧;導(dǎo)入的組件由AutoConfigurationPackages.Registrar.class;

將主配置類(@SpringBootApplication標(biāo)注的類)的所在包及下面所有子包里面的所有組件掃描到Spring容器胎撤;

②. @Import(AutoConfigurationImportSelector.class)

  • @Import:給容器中導(dǎo)入組件
  • EnableAutoConfigurationImportSelector是導(dǎo)入哪些組件的選擇器晓殊;
  • 將所有需要導(dǎo)入的組件以全類名的方式返回;這些組件就會被添加到容器中伤提;
  • 給容器中導(dǎo)入非常多的自動配置類(xxxAutoConfiguration)巫俺;就是給容器中導(dǎo)入這個場景需要的所有組件,并配置好這些組件肿男;

有了自動配置類介汹,免去了我們手動編寫配置注入功能組件等的工作却嗡;

SpringFactoriesLoader.loadFactoryNames(EnableAutoConfiguration.class,classLoader);Spring Boot在啟動的時候從類路徑下的META-INF/spring.factories中獲取EnableAutoConfiguration指定的值嘹承,將這些值作為自動配置類導(dǎo)入到容器中窗价,自動配置類就生效,幫我們進行自動配置工作叹卷;以前我們需要自己配置的東西撼港,自動配置類都幫我們;

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末骤竹,一起剝皮案震驚了整個濱河市帝牡,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌蒙揣,老刑警劉巖靶溜,帶你破解...
    沈念sama閱讀 218,941評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異懒震,居然都是意外死亡罩息,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評論 3 395
  • 文/潘曉璐 我一進店門个扰,熙熙樓的掌柜王于貴愁眉苦臉地迎上來瓷炮,“玉大人,你說我怎么就攤上這事锨匆≌副穑” “怎么了冬筒?”我有些...
    開封第一講書人閱讀 165,345評論 0 356
  • 文/不壞的土叔 我叫張陵恐锣,是天一觀的道長。 經(jīng)常有香客問我舞痰,道長土榴,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,851評論 1 295
  • 正文 為了忘掉前任响牛,我火速辦了婚禮玷禽,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘呀打。我一直安慰自己矢赁,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,868評論 6 392
  • 文/花漫 我一把揭開白布贬丛。 她就那樣靜靜地躺著撩银,像睡著了一般。 火紅的嫁衣襯著肌膚如雪豺憔。 梳的紋絲不亂的頭發(fā)上额获,一...
    開封第一講書人閱讀 51,688評論 1 305
  • 那天够庙,我揣著相機與錄音,去河邊找鬼抄邀。 笑死耘眨,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的境肾。 我是一名探鬼主播剔难,決...
    沈念sama閱讀 40,414評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼准夷!你這毒婦竟也來了钥飞?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,319評論 0 276
  • 序言:老撾萬榮一對情侶失蹤衫嵌,失蹤者是張志新(化名)和其女友劉穎读宙,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體楔绞,經(jīng)...
    沈念sama閱讀 45,775評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡结闸,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了酒朵。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片桦锄。...
    茶點故事閱讀 40,096評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖蔫耽,靈堂內(nèi)的尸體忽然破棺而出结耀,到底是詐尸還是另有隱情,我是刑警寧澤匙铡,帶...
    沈念sama閱讀 35,789評論 5 346
  • 正文 年R本政府宣布图甜,位于F島的核電站,受9級特大地震影響鳖眼,放射性物質(zhì)發(fā)生泄漏黑毅。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,437評論 3 331
  • 文/蒙蒙 一钦讳、第九天 我趴在偏房一處隱蔽的房頂上張望矿瘦。 院中可真熱鬧,春花似錦愿卒、人聲如沸缚去。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽易结。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間衬衬,已是汗流浹背买猖。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評論 1 271
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留滋尉,地道東北人玉控。 一個月前我還...
    沈念sama閱讀 48,308評論 3 372
  • 正文 我出身青樓,卻偏偏與公主長得像狮惜,于是被迫代替她去往敵國和親高诺。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,037評論 2 355

推薦閱讀更多精彩內(nèi)容

  • spring官方文檔:http://docs.spring.io/spring/docs/current/spri...
    牛馬風(fēng)情閱讀 1,684評論 0 3
  • SpringMVC原理分析 Spring Boot學(xué)習(xí) 5碾篡、Hello World探究 1虱而、POM文件 1、父項目...
    jack_jerry閱讀 1,296評論 0 1
  • 本來是準(zhǔn)備看一看Spring源碼的开泽。然后在知乎上看到來一個帖子牡拇,說有一群**自己連Spring官方文檔都沒有完全讀...
    此魚不得水閱讀 6,935評論 4 21
  • @Conponent組件:沒有明確的角色。 @Servise:在業(yè)務(wù)邏輯層使用(service層)穆律。 @Repos...
    berger_w閱讀 1,366評論 0 0
  • springboot 概述 SpringBoot能夠快速開發(fā)惠呼,簡化部署,適用于微服務(wù) 參考嘟嘟大神SpringBo...
    一紙硯白閱讀 5,424評論 2 20