- 1.Spring核心
- 2.Spring注解编程-IOC
- 3.SpringBoot简介
- 4.Spring Boot 入门
- 5.入门探究
1.Spring核心
Spring两大核心:基于工厂模式IOC(DI)和基于动态代理AOP。
- IOC(DI)是指控制器反转(依赖注入),原来要使用某个类对象实例是必须自己创建,使用spring后就不需要自己创建,由spring控制,需要时直接从spring中获取并且有依赖关系是会spring会通过反射自动注入。
- AOP就是不影响这场执行过程的前后加入额外的逻辑。比如权限,日志等,该执行的业务逻辑正常执行知识可以进行权限的判断核日志记录。
2.Spring注解编程-IOC
2.1 引入
以前是通过配置文件的方式注册bean,其实现在spring提倡以注解驱动的方式实现bean的注册
2.2 环境准备
- 创建一个maven项目
- 导包。在pom.xml中粘贴
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.12.RELEASE</version>
</dependency>
2.3 传统方式获取bean
- 在main下的resources下创建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 {
/**
* 传统方式
* @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:加了这个注解的类就是配置类,相当于传统的一个applicationContext-xxx.xml
- @Bean:在标注了@Configuration的类里面的方法上面打上@bean就是注册了这个Bean,相当于在applicationContext-xxx.xml配置的一个<bean id=”userDao” class=”cn.itsource.dao.UserDao”>
注意:bean的名字默认就是方法名,如果想改方法名使用@Bean(“beanName”)
2.4.1.1 配置类&Bean Bean名字
配置类:在类上面打上@Configuration注解
注册Bean:在配置类里面的方法上打上@Bean注解
Bean名字:@Bean注解有个参数name,赋值就可以了
package cn.wangningbo.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.Date;
@Configuration//注解类==配置文件 //告诉spring这是一个注解类 //这个注解的类就相当于传统的一个applicationContext-xxx.xml
public class MainConfig {
// @Bean(name = "nameTest")//自定义了名字就使用自定义的名字
@Bean//未自定义名字就会默认是方法名
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");//未自定义名字就会默认是方法名
// Object myDate = context.getBean("nameTest");//自定义了名字就使用自定义的名字
System.out.println(myDate);
}
2.4.1.2 配置类&Bean&@Scope 单例模式或多例模式
@Scope:用来配置这个类是单例模式还是多例模式,如果不配置,默认就是单例模式
单例模式(singleton):单例类只能有一个实例。
多例模式(prototype):每次获取都是新的实例。
使用方法:@Scope注解有个value参数,赋值就可以了
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这是一个注解类 //这个注解的类就相当于传统的一个applicationContext-xxx.xml
public class MainConfig {
@Bean//未自定义名字就会默认是方法名
@Scope(value = "prototype") //默认是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:配置这个类是否使用懒加载。如果不打这个注解,默认就是迫切加载,打了注解就是懒加载
- 创建一个自己的类,提供构造方法,用于测试
package cn.wangningbo.domain;
public class User {
public User() {
System.out.println("User create...");
}
}
- 配置类里配置
@Configuration//注解类==配置文件 //告诉spring这是一个注解类 //这个注解的类就相当于传统的一个applicationContext-xxx.xml
public class MainConfig {
@Bean
@Lazy//如果不打这个注解,默认就是迫切加载,打了注解就是懒加载
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");//注释掉这一行,没有执行构造方法,就是懒加载!反之就是迫切加载
}
2.4.1.4 配置类&Bean&@Conditional 按照条件注册
@Conditional:满足条件的类才会注册
使用这个注解的类要实现Condition接口才会生效
注意点:@Conditional注解也可以打在类上面
- 准备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 当前方法或注解类的注解类型元数据信息
* @return
*/
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
//常用方法
//1 获取beanFactory
ConfigurableListableBeanFactory beanFactory = conditionContext.getBeanFactory();
//2 获取类家长群
ClassLoader classLoader = conditionContext.getClassLoader();
//3 获取当前运行环境
Environment environment = conditionContext.getEnvironment();
//4 获取bean的注册器,获取手动注册bean到spring容器
BeanDefinitionRegistry registry = conditionContext.getRegistry();
// 5. 获取当前运行环境的名字
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 当前方法或注解类的注解类型元数据信息
* @return
*/
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
//常用方法
//1 获取beanFactory
ConfigurableListableBeanFactory beanFactory = conditionContext.getBeanFactory();
//2 获取类家长群
ClassLoader classLoader = conditionContext.getClassLoader();
//3 获取当前运行环境
Environment environment = conditionContext.getEnvironment();
//4 获取bean的注册器,获取手动注册bean到spring容器
BeanDefinitionRegistry registry = conditionContext.getRegistry();
// 5. 获取当前运行环境的名字
String osName = environment.getProperty("os.name");
if (osName.contains("Windows")) {
return true;
}
return false;
}
}
- 配置类
@Configuration//注解类==配置文件 //告诉spring这是一个注解类 //这个注解的类就相当于传统的一个applicationContext-xxx.xml
public class MainConfig {
@Bean
@Conditional(value = LinuxCondition.class)//根据这个条件决定是否注册
public User userLinux() {
System.out.println("Linux条件成立");
return new User();
}
@Bean
@Conditional(value = WindowsCondition.class)//根据这个条件决定是否注册
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"/>.
然而现在注解驱动开发已经没有了配置文件,不能配置。但是提供了@ComponentScan,我们可以在配置类上面加上这个注解也是一样,并且也能扫描配置包项目的相关注解,也能完成自动注入。
@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这是一个注解类 //这个注解的类就相当于传统的一个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这是一个注解类 //这个注解的类就相当于传统的一个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这是一个注解类 //这个注解的类就相当于传统的一个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 //包含要生效,必须去除默认过滤器
配置类
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这是一个注解类 //这个注解的类就相当于传统的一个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 //包含要生效,必须去除默认过滤器
)
})
public class MainConfig4 {
//不变还使用Bean方式
@Bean
public UserDao userDao() {
return new UserDao();
}
}
2.4.3 @Import
@Import(快速向容器中注册一个bean)
- (1)@Import(要导入的组件),名称就是类的全限定名
- (2)ImportSelector:导入选择器,返回需要导入组件类的全限定名数组-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(要导入的组件),名称就是累的全限定名
* 2)ImportSelector:导入选择器,返回需要导入组件类的全限定名数组-springboot底层用的多
* 3)ImportBeanDefinitionRegistrar:通过bean定义注册器手动项目spring中容器中注册
*/
}
- 准备测试所需要的普通类
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());
//把满足条件的类们的全限定名以数组方式进行返回
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 元数据
* @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注册组件
那个类要实现FactoryBean接口
- 配置类
package cn.wangningbo.factoryBeanTest;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MainConfig6 {
//获取到的不是UserFactoryBean,而是通过这个factorybean创建对象
@Bean
public UserFactoryBean factoryBean(){
return new UserFactoryBean();
}
}
- 类准备
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 总结:注册Bean的4种方式
- @Bean
- name
- scope
- lazy
- conditional
- @ComponentScan/@ComponentScans
- 一个ComponentScan
- exclude
- include
- useDefaultFilters
- 多个ComponentScans
- ComponentScan
- 一个ComponentScan
- @import
- 类名
- 选择器
- 注册器
- factorybean
2.5 Bean的生命周期
Bean生命周期:创建---->初始化---->销毁
我们可以自定义bean的初始化和销毁方法,并进行指定,bean在容器进行到对应生命周期时就会调用对应的方案. xml配置方式 <bean id="userDao" class="cn.itsource.dao.UserDao" init-method="" destroy-method="">
- 创建
单实例bean:在容器创建是就进行指定
多实例bean:在每次使用时创建 - 初始化
容器创建完成,并赋值好,完成初始化 - 销毁
单实例bean:容器关闭时进行销毁
多实例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的生命周期: 创建-初始化-销毁
* 创建:
* 单例:IOC容器已启动就创建(没有配置Lazy)
* 多实例:每次使用
* 初始化:
* 创建完成就初始化
* 销毁:
* 单例:IOC容器关闭
* 多实例:没有关系
* @throws Exception
*/
@Test
public void testLifeCycle() throws Exception {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext
(MainConfig7.class);
System.out.println("ioc容器创建了!");
//第一次获取
Student p = context.getBean(Student.class);
System.out.println("使用对象!");
//关闭掉
System.out.println("ioc容器关闭!");
context.close();
}
}
2.5.2 方式二:接口InitializingBean和DisposableBean
那个类要实现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 {
// 摧毁的时候调用
public void destroy() throws Exception {
System.out.println("Teacher destroy ...");
}
//初始化的时候调用
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容器创建了!");
//第一次获取
Teacher teacher = context.getBean(Teacher.class);
System.out.println("使用对象!");
//关闭掉
System.out.println("ioc容器关闭!");
context.close();
}
2.5.3 方式三:注解@PostConstruct @PreDestroy
在类的某个方法上面加上@PostConstruct,创建实例的时候就会执行这个方法
在类的某个方法上面加上@PreDestroy,销毁实例的时候就会执行这个方法
- 配置类
@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容器创建了!");
//第一次获取
Person person = context.getBean(Person.class);
System.out.println("使用对象!");
//关闭掉
System.out.println("ioc容器关闭!");
context.close();
}
2.5.4 方式四:BeanPostProcessor(接口),bean后置处理器
3.SpringBoot简介
3.1 什么是Spring Boot?
springBoot是Spring项目中的一个子工程,与我们所熟知的Spring-framework 同属于spring的产品。
使用springboot,可以让我们快速的构建庞大的spring项目(包括web 持久化),并且尽可能的减少一切xml配置,做到开箱即用,迅速上手,让我们关注业务而非配置。
3.2 为什么要使用Spring Boot?
它的出现解决了传统spring项目以下的问题:
- 配置负责繁多
每一个组件集成spring都需要编写对应配置文件,比如appplicationContext-xxx.xml - 混乱的依赖管理
在spirng中想集成对应组件时,需要导入N多的pom,并且还有考虑版本。
我们使用SpringBoot创建java应用,只需填写很少配置和依赖就能快速搭建,并使用java –jar 启动它,就能得到一个生产级别的web工程。非常方便
3.3 Spring Boot的特点
- 为所有 Spring 的开发者提供一个非常快速的、广泛接受的入门体验
- 开箱即用(启动器starter-其实就是SpringBoot提供的一个jar包),但通过自己设置参数(.properties),即可快速摆脱这种方式。
- 提供了一些大型项目中常见的非功能性特性,如内嵌服务器、安全、指标,健康检测、外部化配置等
- 绝对没有代码生成,也无需 XML 配置。
用过的都说爽!
4.Spring Boot 入门
4.1 环境要求
- JDK 1.8
- Maven
- idea
4.2 入门
4.2.1 创建maven项目springboot_parent,在pom.xml配置
<!--在父模块中直接管理springboot相关jar的版本-->
<dependencyManagement>
<dependencies>
<!--springboot版本管理,springboot相关模块引入是就不需要制定版本了-->
<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 创建子模块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中设置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使用的是第二种直接设置spring-boot-starter-parent为父亲的方式,则不需要下面这个配置,因为已经默认配置好了
<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右侧的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快速创建Spring Boot项目
IDE都支持使用Spring的项目创建向导快速创建一个Spring Boot项目;
选择我们需要的模块;向导会联网创建Spring Boot项目;
默认生成的Spring Boot项目;
- 主程序已经生成好了,我们只需要我们自己的逻辑
- resources文件夹中目录结构
- static:保存所有的静态资源; js css images;
- templates:保存所有的模板页面;(Spring Boot默认jar包使用嵌入式的Tomcat,默认不支持JSP页面);可以使用模板引擎(freemarker、thymeleaf);
- application.properties:Spring Boot应用的配置文件;可以修改一些默认设置;
5.入门探究
5.1 POM.xml文件
5.1.1 jar版本控制
无论子模块中使用第一种方式还是第二种方式,最终都会找到同一个父亲:spring-boot-dependencies-2.0.5.RELEASE.pom文件!它来真正管理Spring Boot应用里面的所有依赖版本;Spring Boot的版本仲裁中心;
以后我们导入依赖默认是不需要写版本;(没有在dependencies里面管理的依赖自然需要声明版本号)
子模块中如果使用下面这个第二种方式控制jar,那么它的父亲是下面的那种!
子模块中配置jar控制
<!--第二种:直接设置spring-boot-starter-parent为父亲-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.5.RELEASE</version>
</parent>
子模块第二种方式jar控制的父亲
<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相关场景的所有依赖都会导入进来。要用什么功能就导入什么场景的启动器
spring-boot-starter-xxx:spring-boot场景启动器;帮我们导入了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: 来标注一个主程序类,说明这是一个Spring Boot应用
*/
@SpringBootApplication
public class App {
public static void main(String[] args) {
// Spring应用启动起来
SpringApplication.run(App.class, args);
}
}
5.2.1 @SpringBootApplication
SpringBootApplication应用标注在某个类上说明这个类是SpringBoot的主配置类,SpringBoot就应该运行这个类的main方法来启动SpringBoot应用;
点击@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的配置类;
- 标注在某个类上,表示这是一个Spring Boot的配置类;
- @Configuration:配置类上来标注这个注解;
- 配置类 ----- 配置文件;配置类也是容器中的一个组件;@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,给容器中导入一个组件;导入的组件由AutoConfigurationPackages.Registrar.class;
将主配置类(@SpringBootApplication标注的类)的所在包及下面所有子包里面的所有组件扫描到Spring容器;
②. @Import(AutoConfigurationImportSelector.class)
- @Import:给容器中导入组件
- EnableAutoConfigurationImportSelector是导入哪些组件的选择器;
- 将所有需要导入的组件以全类名的方式返回;这些组件就会被添加到容器中;
- 给容器中导入非常多的自动配置类(xxxAutoConfiguration);就是给容器中导入这个场景需要的所有组件,并配置好这些组件;
有了自动配置类,免去了我们手动编写配置注入功能组件等的工作;
SpringFactoriesLoader.loadFactoryNames(EnableAutoConfiguration.class,classLoader);Spring Boot在启动的时候从类路径下的META-INF/spring.factories中获取EnableAutoConfiguration指定的值,将这些值作为自动配置类导入到容器中,自动配置类就生效,帮我们进行自动配置工作;以前我们需要自己配置的东西,自动配置类都帮我们;