SpringBoot原理分析
SpringBoot自动配置
- 快速构建一个模块
自定义Condition
- 创建condition类:
package com.itheima.springbootcondition.condtion;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotatedTypeMetadata;
import java.util.Map;
public class ClassCondition implements Condition {
/**
*
* @param context 上下文对象。用于获取环境,IOC容器,ClassLoader对象
* @param metadata 注解元对象。 可以用于获取注解定义的属性值
* @return
*/
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
//1.需求: 导入Jedis坐标后创建Bean
//思路:判断redis.clients.jedis.Jedis.class文件是否存在
boolean flag = true;
try {
Class<?> cls = Class.forName("redis.clients.jedis.Jedis");
} catch (ClassNotFoundException e) {
flag = false;
}
return flag;
//2.需求: 导入通过注解属性值value指定坐标后创建Bean
//获取注解属性值 value
Map<String, Object> map = metadata.getAnnotationAttributes(ConditionOnClass.class.getName());
//System.out.println(map);
String[] value = (String[]) map.get("value");
boolean flag = true;
try {
for (String className : value) {
Class<?> cls = Class.forName(className);
}
} catch (ClassNotFoundException e) {
flag = false;
}
return flag;
}
}
- 自定义注解:
package com.itheima.springbootcondition.condtion;
import org.springframework.context.annotation.Conditional;
import java.lang.annotation.*;
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(ClassCondition.class)//使用注解时使用自定义条件
public @interface ConditionOnClass {
String[] value();
}
package com.itheima.springbootcondition.config;
import com.itheima.springbootcondition.condtion.ClassCondition;
import com.itheima.springbootcondition.condtion.ConditionOnClass;
import com.itheima.springbootcondition.domain.User;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
@Configuration
public class UserConfig {
@Bean
@Conditional(ClassCondition.class)
@ConditionOnClass("com.alibaba.fastjson.JSON")
public User user(){
return new User();
}
@Bean
@ConditionalOnProperty(name = "itcast",havingValue = "itheima")
public User user2(){
return new User();
}
}
@Import注解
不可以,因为@ComponentScan 扫描范围:当前引导类所在包及其子包
解决方案:
- @ComponsenScan(配置类所在包全限定类名)(不好用)
- @使用Import(XXXConfig.class)注解加载类,这些类会被Spring创建,并加入IOC容器中(不太方便)
- 对Import注解进行封装,使用封装后的注解(@EnableUser)
- 实现ImportSelector类
package com.itheima.config;
import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;
public class MyImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{"com.itheima.domain.User", "com.itheima.domain.Role"};
}
}
再Import(MyImpotySelector.class)
- 实现ImportBeanDefinitionRegistrar类
package com.itheima.config;
import com.itheima.domain.User;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.rootBeanDefinition(User.class).getBeanDefinition();
registry.registerBeanDefinition("user", beanDefinition);
}
}
再Import(MyImportBeanDefinitionRegistrar.class)
@EnableAutoConfiguration注解
SpringBoot的底层实现原理是什么?
通过@EnableAutoConfiguration注解加载Springboot内置的自动初始化类(加载什么类是配置在spring.factories),在这些类中在基于spring4.0提供的Condition接口进行Bean的初始化。
自定义starter步骤分析
-
创建autoconfigure工程
-
定义我们模块所提供的功能配置类
- 注意通过条件判断,防止Bean冲突@ConditionalOnMissingBean(name = “jedis”)
-
编写META-INF/spring.factories文件
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.itheima.redis.config.RedisAutoConfiguration
-
-
创建starter工程(遵循Spring starter命名规范)
- 导入autoconfigure
package com.itheima.redis.config;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import redis.clients.jedis.Jedis;
@Configuration
@EnableConfigurationProperties(RedisProperties.class)//让RedisProperties配Spring识别
@ConditionalOnClass(Jedis.class)
public class RedisAutoConfiguration {
/**
* 提供Jedis的bean
*/
@Bean
@ConditionalOnMissingBean(name = "jedis")
public Jedis jedis(RedisProperties redisProperties) {
System.out.println("RedisAutoConfiguration....");
return new Jedis(redisProperties.getHost(), redisProperties.getPort());
}
}
package com.itheima.redis.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties(prefix = "redis")
public class RedisProperties {
private String host = "localhost";
private int port = 6379;
public String getHost() {
return host;
}
public void setHost(String host) {
this.host = host;
}
public int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
}
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.itheima.redis.config.RedisAutoConfiguration
package com.itheima.springbootenable;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import redis.clients.jedis.Jedis;
import java.util.Map;
/**
* @ComponentScan 扫描范围:当前引导类所在包及其子包
*
* com.itheima.springbootenable
* com.itheima.config
* //1.使用@ComponentScan扫描com.itheima.config包
* //2.可以使用@Import注解,加载类。这些类都会被Spring创建,并放入IOC容器
* //3.可以对Import注解进行封装。
*/
/**
* Import4中用法:
* 1. 导入Bean
* 2. 导入配置类
* 3. 导入ImportSelector的实现类。
* 4. 导入ImportBeanDefinitionRegistrar实现类
*/
//@ComponentScan("com.itheima.config")
//@Import(UserConfig.class)
//@EnableUser
//@Import(User.class)
//@Import(UserConfig.class)
//@Import(MyImportSelector.class)
//@Import({MyImportBeanDefinitionRegistrar.class})
@SpringBootApplication
public class SpringbootEnableApplication {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(SpringbootEnableApplication.class, args);
/*//获取Bean
Object user = context.getBean("user");
System.out.println(user);*/
/*User user = context.getBean(User.class);
System.out.println(user);
Role role = context.getBean(Role.class);
System.out.println(role);*/
/* Object user = context.getBean("user");
System.out.println(user);*/
/* Map<String, User> map = context.getBeansOfType(User.class);
System.out.println(map);*/
Jedis jedis = context.getBean(Jedis.class);
System.out.println(jedis);
jedis.set("name","itcast");
String name = jedis.get("name");
System.out.println(name);
}
@Bean
public Jedis jedis(){
return new Jedis("localhost",6379);
}
}
SpringBoot监听机制
-
程序之后执行:
- ApplicationRunner:SpringBoot启动完成后被调用,参数是ApplicationArguments
- CommandLineRunner:SpringBoott启动完成后被调用,参数是String
-
程序启动过程中:
-
实现过程的事件监听器
public class SpringContextListenerTest implements ApplicationListener<ApplicationStartingEvent > { @Override public void onApplicationEvent(ApplicationStartingEvent applicationStartingEvent) { System.out.println("我是菩萨,保佑你无BUG!!!"); } }
-
在spring启动类中添加监听器
public static void main(String[] args) { SpringApplication app = new SpringApplication(SpringbootListenerApplication.class); // app.addInitializers(new MyApplicationContextInitializer()); app.addListeners( new SpringContextListenerTest()); app.run(args); }
-
-
SpringApplicationRunListener:提供全生命周期的事件监听【了解】
-
ApplicationContextInitializer :监听Conetext开始创建的时候【了解】
package com.itheima.springbootlistener;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringbootListenerApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootListenerApplication.class, args);
}
}
package com.itheima.springbootlistener.listener;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.stereotype.Component;
@Component
public class MyApplicationContextInitializer implements ApplicationContextInitializer {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
System.out.println("ApplicationContextInitializer....initialize");
}
}
package com.itheima.springbootlistener.listener;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
import java.util.Arrays;
/**
* 当项目启动后执行run方法。
*/
@Component
public class MyApplicationRunner implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) throws Exception {
System.out.println("ApplicationRunner...run");
System.out.println(Arrays.asList(args.getSourceArgs()));
}
}
package com.itheima.springbootlistener.listener;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
import java.util.Arrays;
@Component
public class MyCommandLineRunner implements CommandLineRunner {
@Override
public void run(String... args) throws Exception {
System.out.println("CommandLineRunner...run");
System.out.println(Arrays.asList(args));
}
}
package com.itheima.springbootlistener.listener;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringApplicationRunListener;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.stereotype.Component;
public class MySpringApplicationRunListener implements SpringApplicationRunListener {
public MySpringApplicationRunListener(SpringApplication application, String[] args) {
}
@Override
public void starting() {
System.out.println("starting...项目启动中");
}
@Override
public void environmentPrepared(ConfigurableEnvironment environment) {
System.out.println("environmentPrepared...环境对象开始准备");
}
@Override
public void contextPrepared(ConfigurableApplicationContext context) {
System.out.println("contextPrepared...上下文对象开始准备");
}
@Override
public void contextLoaded(ConfigurableApplicationContext context) {
System.out.println("contextLoaded...上下文对象开始加载");
}
@Override
public void started(ConfigurableApplicationContext context) {
System.out.println("started...上下文对象加载完成");
}
@Override
public void running(ConfigurableApplicationContext context) {
System.out.println("running...项目启动完成,开始运行");
}
@Override
public void failed(ConfigurableApplicationContext context, Throwable exception) {
System.out.println("failed...项目启动失败");
}
}
org.springframework.context.ApplicationContextInitializer=com.itheima.springbootlistener.listener.MyApplicationContextInitializer
org.springframework.boot.SpringApplicationRunListener=com.itheima.springbootlistener.listener.MySpringApplicationRunListener
SpringBoot启动流程分析
SpringBoot监控
SpringBoot监控概述
Spring Boot Admin
- 服务器安装
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-server</artifactId>
</dependency>
// 开启admin服务功能
@EnableAdminServer
@SpringBootApplication
public class SpringbootAdminServerApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootAdminServerApplication.class, args);
}
}
- 客户端
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-client</artifactId>
</dependency>
# 指定adminserver的地址
spring.boot.admin.client.url=http://localhost:9000
SpringBoot项目部署
- SprinBoot项目开发完毕后,支持两种方式部署到服务器:
1.jar包(官方推荐)
2.war包 - 改造启动类
@SpringBootApplication
public class SpringbootDeployApplication extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(SpringbootDeployApplication.class, args);
}
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return builder.sources(SpringbootDeployApplication.class);
}
}
- 改造POM.xml
<packaging>war</packaging>