springboot-01

回调模式的概念

  回调模式是指:如果一个方法的参数是接口类型,则在调用该方法时,需要创建并传递一个实现此接口类型的对象;而该方法在运行时会调用到参数对象中所实现的方法(接口中定义的)。

匿名类

接口/父类类型 引用变量名 = new 接口/父类类型(){方法的重写};

1、

/*
basicConsume(String queue, boolean autoAck, Consumer callback)
        参数:
            1. queue:队列名称
            2. autoAck:是否自动确认
            3. callback:回调对象

*/
        // 接收消息
        Consumer consumer = new DefaultConsumer(channel){

 /*               回调方法,当收到消息后,会自动执行该方法

                1. consumerTag:标识
                2. envelope:获取一些信息,交换机,路由key...
                3. properties:配置信息
                4. body:数据
*/
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                System.out.println("consumerTag:"+consumerTag);
	 }
};

channel.basicConsume("hello_world",true,consumer);

2、

 /**
     * 确认模式:
     * 步骤:
     * 1. 确认模式开启:ConnectionFactory中开启publisher-confirms="true"
     * 2. 在rabbitTemplate定义ConfirmCallBack回调函数
     */
    @Test
    public void testConfirm() {

        //2. 定义回调
        rabbitTemplate.setConfirmCallback(new RabbitTemplate.ConfirmCallback() {
            /**
             *
             * @param correlationData 相关配置信息
             * @param ack   exchange交换机 是否成功收到了消息。true 成功,false代表失败
             * @param cause 失败原因
             */
            @Override
            public void confirm(CorrelationData correlationData, boolean ack, String cause) {
                System.out.println("confirm方法被执行了....");

                if (ack) {
                    //接收成功
                    System.out.println("接收成功消息" + cause);
                } else {
                    //接收失败
                    System.out.println("接收失败消息" + cause);
                    //做一些处理,让消息再次发送。
                }
            }
        });
public class RabbitTemplate{
        @FunctionalInterface
    public interface ConfirmCallback {
		...
    }
}

自动配置

​ ---基于spring的java配置类的方式完成和第三方框架的整合

springboot --> 提供一种快速使用spring的方式

spring的配置 java配置类

1、基于xml的配置

2、基于Java的配置! --》提供一些配置类即可

@Configuration 表明是一个注解类

1、@Configuration

@Configuration标注在类上相当于把该类作为spring的xml配置文件中的<beans>,作用为:配置spring容器(应用上下文)

@Configuration
public class TestConfiguration {
    public TestConfiguration() {
        System.out.println("TestConfiguration容器启动初始化。。。");
    }
}

||

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" 
       ...
http://www.springframework.org/schema/task/spring-task-4.0.xsd" default-lazy-init="false">


</beans>
2、@Configuration+@Bean

@Configuration启动容器+@Bean注册Bean,@Bean下管理bean的生命周期

@Bean标注在方法上(返回某个实例的方法),等价于spring的xml配置文件中的<bean>,作用为:注册bean对象

3、@Configuration+@Component+@ComponentScan

@Configuration启动容器+@Component注册Bean +@ComponentScan(basePackages = "com.dxz.demo.configuration")扫描包中注解所标 注的类,如@Component、@Service、@Controller、@Repository。

小结

@Configuation等价于

@Bean等价于

@ComponentScan等价于<context:component-scan base-package=”com.zhu.demo”/>

注解

元注解:

  • @Target /目标

    用于声明注解的作用范围,例如作用范围为类、接口、方法等。

  • @Retention /保留

    声明了注解的生命周期,即注解在什么范围内有效。

  • @Documented /文档

    是一个标记注解,有该注解的注解会在生成 java 文档中保留。

  • @Inherited /继承

    表示修饰的自定义注解可以被子类继承

https://blog.51cto.com/13586365/2065324

https://www.fangzhipeng.com/java/2017/09/16/java-annotation.html

spEL

即Spring表达式语言

可以在运行时查询和操作数据

https://www.jianshu.com/p/e0b50053b5d3

测试类

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfig.class)
//@RunWith(SpringRunner.class)
@RunWith(SpringJUnit4ClassRunner.class)
//@SpringBootTest(classes = Demo01Application.class)
@SpringBootTest
//如果在引导类包的子包里(在test包下,包名一样),就不需要引导类.class了
1、@RunWith

@RunWith 就是一个运行器

@RunWith(SpringJUnit4ClassRunner.class)

​ 让测试运行于Spring测试环 境,以便在测试开始的时候自动创建Spring的应用上下文

2、@ContextConfiguration和@SpringBootTest

https://www.cnblogs.com/bihanghang/p/10023759.html

Spring的条件装配

    public @interface Conditional {
        Class<? extends Condition>[] value();
        /*
                该注解可以接收一个Condition 的数组
                Class类型的数组,可以存储Condition或者实现类
         */
        
        /*   ArrayList<? extends Number>
            //带通配符的泛型集合不能使用add方法
        */
    }
  • 自定义注解

    • 需要传入一个Class数组,并且需要继承Condition接口

    • 格式

      • public @interface 注解名称{
        	public 属性类型 属性名() default 默认值;
        }
        
  • 泛型

    • 类型通配符:<?>

    • 类型通配符上限:<? extends Number>

      • 类型是Number或者其子类型

      • ?都继承自Number,都在他下面

    • 类型通配符下限:<? super Number>

      • 类型是Number或者其父类型

      • ? 都比Number更大,都在他上面

  • Class类

@Conditional注解可以添加在@Configuration、@Component、@Service等修饰的类上用于控制对应的Bean是否需要创建,或者添加在@Bean修饰的方法上用于控制方法对应的Bean是否需要创建。

@Conditional添加在@Configuration修饰的类上,用于控制该类和该类里面所有添加的@Bean方法对应的Bean是否需要创建。

Condition接口

    /**
     * context  上下文对象。用于获取环境,IOC容器,ClassLoader对象
     * metadata 注解元对象。 可以用于获取注解定义的属性值
     *          应用:导入通过注解值value指定坐标后创建Bean
     *          metadata.getAnnotationAttributes(ConditionOnClass.class.getName());
     *              //Class.getNume()获取全类名
     *              //ConditionOnClass 实现了Condition接口的注解
     */
    public interface Condition {
        boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);
    }

切换内置服务器

---默认使用Tomcat服务器

步骤

  1. 排除掉tomcat
  2. 引入别的依赖

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

@Enable* 注解

作用:用于动态启用某些功能的 =》加载@Configure配置类

底层是使用@Import注解导入一些配置类,实现Bean的动态加载

问题:SpringBoot工程是否可以直接获取jar包中定义的Bean? 不能

原因:@ComponentScan 扫描范围 :当前引导类所在的包及其子包

解决:

  1. 使用@ComponentScan 扫描

    1. @SpringBootApplication
      @ComponentScan("com.config")
      
  2. 使用@Import加载类,这些bean都会被spring创建,并放入到ioc容器

    1. public @interface Import {
      	Class<?>[] value(); //可以存任意的.class
          //ArrayList<?> 可以存任意
      }
      
    2. @SpringBootApplication
      @Import(UserConfig.class)
      
  3. @Import进行封装 -》 @Enable*

    1. @Target(ElementType.TYPE)
      @Retention(RetentionPolicy.RUNTIME)
      @Documented
      public @interface Import {
      	Class<?>[] value();
      }
      
    2. @Target(ElementType.TYPE)
      @Retention(RetentionPolicy.RUNTIME)
      @Documented                 //把Import注解上面的东西加进来,不可少
      @Import(UserConfig.class)
      public @interface EnableUser {
      
      }
      

@Import详解

  1. 导入Bean

  2. 导入配置类

  3. 导入ImportSelector实现类,一般用于加载配置文件中的类

    1. public interface ImportSelector {
      	/**
      	 * Select and return the names of which class(es) should be imported based on
      	 * the {@link AnnotationMetadata} of the importing @{@link Configuration} class.
      	 * @return the class names, or an empty array if none
      	 */
      	String[] selectImports(AnnotationMetadata importingClassMetadata);
      }
      
  4. 导入ImportBeanDefinitionRegistrar实现类

    1. public interface ImportBeanDefinitionRegistrar {
      
      	/**
      	 * Register bean definitions as necessary based on the given annotation metadata of
      	 * the importing {@code @Configuration} class.
      	 * <p>Note that {@link BeanDefinitionRegistryPostProcessor} types may <em>not</em> be
      	 * registered here, due to lifecycle constraints related to {@code @Configuration}
      	 * class processing.
      	 * @param importingClassMetadata annotation metadata of the importing class
      	 * @param registry current bean definition registry
      	 */
      	void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry);
      }
      
    2. 使用

      public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
              AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.rootBeanDefinition(User.class).getBeanDefinition();
              registry.registerBeanDefinition("user", beanDefinition);
          }
      

@EnableAutoConfiguration

  1. @Import(AutoConfigurationImportSelector.class)
    public @interface EnableAutoConfiguration {
    }
    
  2. public class AutoConfigurationImportSelector implements DeferredImportSelector... 
    {
        	@Override
    	public String[] selectImports(AnnotationMetadata annotationMetadata) {
    		AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(autoConfigurationMetadata,
    				annotationMetadata);  //加载
    		return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());//返回字符串数组
    	}
    }
    
  3. 	protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata,
       			AnnotationMetadata annotationMetadata) {
       		if (!isEnabled(annotationMetadata)) {
       			return EMPTY_ENTRY;
       		}
       		AnnotationAttributes attributes = getAttributes(annotationMetadata);
       		List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
       		configurations = removeDuplicates(configurations);
       		Set<String> exclusions = getExclusions(annotationMetadata, attributes);
       		checkExcludedClasses(configurations, exclusions);
       		configurations.removeAll(exclusions);
       		configurations = filter(configurations, autoConfigurationMetadata);
       		fireAutoConfigurationImportEvents(configurations, exclusions);
       		return new AutoConfigurationEntry(configurations, exclusions);
       	}
    
  4. 	protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
       		List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
       				getBeanClassLoader());
       		Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you "
       				+ "are using a custom packaging, make sure that file is correct.");
       		return configurations;
       	}
    
  5. 例如

    1. org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
      org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration
      
    2. @Configuration
      @ConditionalOnClass({RedisOperations.class}) //条件
      @EnableConfigurationProperties({RedisProperties.class})
      @Import({LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class})
      public class RedisAutoConfiguration {
          public RedisAutoConfiguration() {
          }
          @Bean
          @ConditionalOnMissingBean(
              name = {"redisTemplate"}
          )
          public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
              return template;
          }
      
      

自定义一个starter

自己整合 分析mybatis

  1. 依赖

    1. <dependency>
      	<groupId>org.springframework.boot</groupId>
      	<artifactId>spring-boot-starter</artifactId>
      </dependency>
      
  2. 依赖传递

    1.    <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-autoconfigure</artifactId>
            <version>2.1.17.RELEASE</version>
            <scope>compile</scope>
          </dependency>
      

自定义redis-starter步骤

  1. 自定义配置类工程redis-spring-boot-autoconfigure

    1. 导入相关依赖,引入jedis依赖

    2. 编写属性配置类,用于加载redis相关配置

      1. @ConfigurationProperties(prefix = "redis")
        public class RedisProperties {
            private String host = "localhost";
            private int port = 6379;
            //	get/set
        }
        
    3. 编写@Configuration配置类并实现条件装配

      1. @Configuration
        @EnableConfigurationProperties(RedisProperties.class)
        public class RedisAutoConfiguration {
            /**
             * 提供Jedis的bean
             */
            @Bean
            @ConditionalOnMissingBean(name = "jedis")
            public Jedis jedis(RedisProperties redisProperties) {  
                return new Jedis(redisProperties.getHost(), redisProperties.getPort());
            }
        }
        
    4. 在META-INF/spring.factories中配置

      1. 在项目的resource目录下创建META-INF文件夹并创建spring.factories,内容如下
        
        org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
          com.itheima.redis.config.RedisAutoConfiguration
        
  2. 自定义起步依赖工程redis-spring-boot-starter

    1. 导入前面的依赖

SpringBoot监听机制

其实是对java提供的事件监听机制的封装

​ java监听机制定义了一下几个角色:

  1. 事件:Event,继承java.util.EventObject类的对象
  2. 事件源:Source,任意对象Object
  3. 监听器:Listener,实现java.util.EventListener接口的对象

SpringBoot在项目启动时,会对几个监听器进行回调,我们可以实现这些监听接口,在项目启动时,完成一些操作

  1. ApplicationContextInitializer

    1. 需要配置

  2. SpringApplicationRunListener

  3. Runner

    1. 当项目启动时,自动装配

    2. CommandLineRunner

    3. ApplicationRunner

SpringBoot启动流程

posted @ 2020-10-14 11:33  风冰水  阅读(100)  评论(0编辑  收藏  举报