回调模式的概念
回调模式是指:如果一个方法的参数是接口类型,则在调用该方法时,需要创建并传递一个实现此接口类型的对象;而该方法在运行时会调用到参数对象中所实现的方法(接口中定义的)。
匿名类
接口/父类类型 引用变量名 = 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类
- 类加载与Class对象
- https://zhuanlan.zhihu.com/p/60294147
- 类是对象的模板,Class是类的模板
- 类加载与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服务器
步骤
- 排除掉tomcat
- 引入别的依赖
<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 扫描范围 :当前引导类所在的包及其子包
解决:
-
使用
@ComponentScan
扫描-
@SpringBootApplication @ComponentScan("com.config")
-
-
使用
@Import
加载类,这些bean都会被spring创建,并放入到ioc容器-
public @interface Import { Class<?>[] value(); //可以存任意的.class //ArrayList<?> 可以存任意 }
-
@SpringBootApplication @Import(UserConfig.class)
-
-
对
@Import
进行封装 -》 @Enable*-
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Import { Class<?>[] value(); }
-
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented //把Import注解上面的东西加进来,不可少 @Import(UserConfig.class) public @interface EnableUser { }
-
@Import详解
-
导入Bean
-
导入配置类
-
导入ImportSelector实现类,一般用于加载配置文件中的类
-
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); }
-
-
导入ImportBeanDefinitionRegistrar实现类
-
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); }
-
使用
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.rootBeanDefinition(User.class).getBeanDefinition(); registry.registerBeanDefinition("user", beanDefinition); }
-
@EnableAutoConfiguration
-
@Import(AutoConfigurationImportSelector.class) public @interface EnableAutoConfiguration { }
-
public class AutoConfigurationImportSelector implements DeferredImportSelector... { @Override public String[] selectImports(AnnotationMetadata annotationMetadata) { AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(autoConfigurationMetadata, annotationMetadata); //加载 return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());//返回字符串数组 } }
-
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); }
-
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; }
-
例如
-
org.springframework.boot.autoconfigure.EnableAutoConfiguration= org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration
-
@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
-
依赖
-
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency>
-
-
依赖传递
-
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-autoconfigure</artifactId> <version>2.1.17.RELEASE</version> <scope>compile</scope> </dependency>
-
自定义redis-starter步骤
-
自定义配置类工程redis-spring-boot-autoconfigure
-
导入相关依赖,引入jedis依赖
-
编写属性配置类,用于加载redis相关配置
-
@ConfigurationProperties(prefix = "redis") public class RedisProperties { private String host = "localhost"; private int port = 6379; // get/set }
-
-
编写@Configuration配置类并实现条件装配
-
@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()); } }
-
-
在META-INF/spring.factories中配置
-
在项目的resource目录下创建META-INF文件夹并创建spring.factories,内容如下 org.springframework.boot.autoconfigure.EnableAutoConfiguration= com.itheima.redis.config.RedisAutoConfiguration
-
-
-
自定义起步依赖工程redis-spring-boot-starter
- 导入前面的依赖
SpringBoot监听机制
其实是对java提供的事件监听机制的封装
java监听机制定义了一下几个角色:
- 事件:Event,继承java.util.EventObject类的对象
- 事件源:Source,任意对象Object
- 监听器:Listener,实现java.util.EventListener接口的对象
SpringBoot在项目启动时,会对几个监听器进行回调,我们可以实现这些监听接口,在项目启动时,完成一些操作
-
ApplicationContextInitializer
-
需要配置
-
-
SpringApplicationRunListener
-
Runner
-
当项目启动时,自动装配
-
CommandLineRunner
-
ApplicationRunner
-