- 1.Spring核心
- 2.Spring注解編程-IOC
- 3.SpringBoot簡介
- 4.Spring Boot 入門
- 5.入門探究
1.Spring核心
Spring兩大核心:基于工廠模式IOC(DI)和基于動態(tài)代理AOP。
- IOC(DI)是指控制器反轉(zhuǎn)(依賴注入)诸迟,原來要使用某個類對象實例是必須自己創(chuàng)建茸炒,使用spring后就不需要自己創(chuàng)建愕乎,由spring控制,需要時直接從spring中獲取并且有依賴關(guān)系是會spring會通過反射自動注入壁公。
- 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)備
- 創(chuàng)建一個maven項目
- 導(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
- 在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>
- 測試。這里會打印出時間润努,測試成功关斜!
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注解
- @Configuration:加了這個注解的類就是配置類,相當(dāng)于傳統(tǒng)的一個applicationContext-xxx.xml
- @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)就是迫切加載授账,打了注解就是懶加載
- 創(chuàng)建一個自己的類,提供構(gòu)造方法惨驶,用于測試
package cn.wangningbo.domain;
public class User {
public User() {
System.out.println("User create...");
}
}
- 配置類里配置
@Configuration//注解類==配置文件 //告訴spring這是一個注解類 //這個注解的類就相當(dāng)于傳統(tǒng)的一個applicationContext-xxx.xml
public class MainConfig {
@Bean
@Lazy//如果不打這個注解白热,默認(rèn)就是迫切加載,打了注解就是懶加載
public User user() {
return new User();
}
}
- 測試方法
/**
* 懶加載 測試
*
* @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注解也可以打在類上面
- 準(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;
}
}
- 配置類
@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();
}
}
- 測試
/**
* 條件注冊 測試
*
* @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 = "包路徑")
- 配置類
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();
}
}
- dao
package cn.wangningbo.dao;
public class UserDao {
public void addUser() {
System.out.println("add user ....");
}
}
- 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();
}
}
- 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();
}
}
- 測試
/**
* 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中容器中注冊
- 配置類
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中容器中注冊
*/
}
- 準(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));
}
}
- 測試
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接口
- 配置類
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();
}
}
- 類準(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;
}
}
- 測試
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種方式
- @Bean
- name
- scope
- lazy
- conditional
- @ComponentScan/@ComponentScans
- 一個ComponentScan
- exclude
- include
- useDefaultFilters
- 多個ComponentScans
- ComponentScan
- 一個ComponentScan
- @import
- 類名
- 選擇器
- 注冊器
- 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="">
- 創(chuàng)建
單實例bean:在容器創(chuàng)建是就進行指定
多實例bean:在每次使用時創(chuàng)建 - 初始化
容器創(chuàng)建完成,并賦值好煌恢,完成初始化 - 銷毀
單實例bean:容器關(guān)閉時進行銷毀
多實例bean:沒有受spring管理骇陈,具體什么時候銷毀有用戶決定。
2.5.1 方式一:@Bean
- 配置類
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();
}
}
- 普通類
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.....");
}
}
- 測試
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這兩個接口
- 配置類
@Configuration
@ComponentScan(value = "cn.wangningbo.lifeCycle")
public class MainConfig7 {
@Bean
public Teacher teacher() {
return new Teacher();
}
}
- 普通類
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 ...");
}
}
- 測試
@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í)行這個方法
- 配置類
@Configuration
@ComponentScan(value = "cn.wangningbo.lifeCycle")
public class MainConfig7 {
@Bean
public Person person() {
return new Person();
}
}
- 普通類
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 ...");
}
}
- 測試
@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項目以下的問題:
- 配置負責(zé)繁多
每一個組件集成spring都需要編寫對應(yīng)配置文件奥务,比如appplicationContext-xxx.xml - 混亂的依賴管理
在spirng中想集成對應(yīng)組件時,需要導(dǎo)入N多的pom袜硫,并且還有考慮版本氯葬。
我們使用SpringBoot創(chuàng)建java應(yīng)用,只需填寫很少配置和依賴就能快速搭建婉陷,并使用java –jar 啟動它帚称,就能得到一個生產(chǎn)級別的web工程官研。非常方便
3.3 Spring Boot的特點
- 為所有 Spring 的開發(fā)者提供一個非常快速的闯睹、廣泛接受的入門體驗
- 開箱即用(啟動器starter-其實就是SpringBoot提供的一個jar包)戏羽,但通過自己設(shè)置參數(shù)(.properties),即可快速擺脫這種方式楼吃。
- 提供了一些大型項目中常見的非功能性特性始花,如內(nèi)嵌服務(wù)器、安全孩锡、指標(biāo)酷宵,健康檢測、外部化配置等
- 絕對沒有代碼生成躬窜,也無需 XML 配置浇垦。
用過的都說爽!
4.Spring Boot 入門
4.1 環(huán)境要求
- JDK 1.8
- Maven
- 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 編碼測試
- 新建啟動類
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);
}
}
- 新建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";
}
}
- 測試
啟動App類中的main方法即可
打開瀏覽器訪問地址:http://localhost:8080/hello
-
注意點
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包所在的目錄那里打開黑窗口
- windows下運行:
運行命令:java -jar xxx.jar - 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這兩個注解
- @SpringBootConfiguration:Spring Boot的配置類坐搔;
- 標(biāo)注在某個類上藏研,表示這是一個Spring Boot的配置類;
- @Configuration:配置類上來標(biāo)注這個注解概行;
- 配置類 ----- 配置文件蠢挡;配置類也是容器中的一個組件;@Component
- @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)入到容器中窗价,自動配置類就生效,幫我們進行自動配置工作叹卷;以前我們需要自己配置的東西撼港,自動配置類都幫我們;