1.自定义注解本身是没有功能的,让注解生效是你如何使用注解,比如拦截指定自定义注解
1.1IDEA创建自定义注解:new - java class - annotation
2.el表达式有默认值
@Value("${property:default value}")
比如 @Value("${mongodb.url:127.0.0.1}")
3.@PropertySource可以指定文件地址
4.@Profile 可与spring.profiles.active一起使用
比如设置环境变量-Dspring.profiles.active=dev或者application.yml种指定spring.profiles.active:dev 会执行被@Profile("dev")注解的方法
(不一定非得spring.profiles.active ,是一个可以从配置文件中读到的属性就好,可以给他一个默认值)
5.spring的监听事件:观察者模式
5.1.自定义事件类继承ApplicationEvent
5.2.监听器实现ApplicationListener
5.3.监听器重写onApplicationEvent方法,监听1.中自定义事件类
5.4.发布publishEvent自定义事件类
5.6可以用@EventListener注解,更方便
Spring事件监听器之@EventListener原理分析_java_脚本之家
Spring为我们提供的一个事件监听、订阅的实现,内部实现原理是观察者设计模式;为的就是业务系统逻辑的解耦,提高可扩展性以及可维护性。事件发布者并不需要考虑谁去监听,监听具体的实现内容是什么,发布者的工作只是为了发布事件而已。
在spring中我们可以通过实现ApplicationListener接口或者@EventListener接口来实现事件驱动编程
比如我们做一个电商系统,用户下单支付成功后,我们一般要发短信或者邮箱给用户提示什么的,这时候就可以把这个通知业务做成一个单独事件监听,等待通知就可以了;把它解耦处理。
public class OrderEvent extends ApplicationEvent {
public OrderEvent(Object source) {
super(source);
}
}
@Component
public class OrderEventListener {
@EventListener
public void listener(OrderEvent event) {
System.out.println("i do OrderEventListener" );
}
}
@Controller
@RequestMapping("person")
public class PersonController implements ApplicationContextAware {
private ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
@ResponseBody
@GetMapping("publishOrderEvent")
public String publishOrderEvent() {
applicationContext.publishEvent(new OrderEvent("我发布了事件!!!"));
System.out.println(" publishOrderEvent ");
return "发送事件了!";
}
}
5.7监听是同步的
如果要改为异步,需使用@Async注解
5.8事务提交之后再执行监听方法
@EventListener
改为
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT,fallbackExecution = true)
6.@Async注解
注解在方法上表名该方法是一个异步方法
注解在类上表名该类所有的方法都是异步方法
7.spring提供了很多@Enable*注解
如@EnableAsync开启异步,@EnableSchedule开启定时,
@EnableConfigurationProperties开启对@ConfigurationProperties的支持(当然 如果@ConfigurationProperties结合@Component注解一起使用,也可以不用@EnableConfigurationProperties注解)
8.@EnableSchedule
使用@Schedule注解,定时执行被@Schedule注解的方法,如@Schedule(cron="")或者@Schedule(多久执行一次)
9.条件注解@Conditional
9.1@Conditional根据满足某一个指定条件创建一个特定的bean
@Conditional(A.class)
其中A实现了Condition接口并且重写了matches方法,其中matches方法是boolean型的,如果返回true,则创建被@Condition注解的bean,如果false,则不创建该bean
9.2@ConditionalOnMissingBean与@ConditionalOnBean含义正好相反
9.3@ConditionalOnBean和@ConditionalOnClass的区别:class是存在这个类就返回true,bean是必须是一个被spring管理的bean,比如他必须有@Component注解
10.@ConfigurationProperties(prefix="xx")
同样是从配置文件中取值,我理解@Value和@ConfigurationProperties的区别
10.1@Value是一个值一个值取,@ConfigurationProperties是根据前缀一堆一堆取值
10.2@ConfigurationProperties用在类上,对应属性有get,set方法
10.3@Value只能从application.yml/properties文件中取值,@ConfigurationProperties可以结合@PropertySource从其他配置文件中取值,比如@PropertySource(value = {"classpath:user.properties"})
11.老生常谈的@Controller和@RestController
@Controller根据配置的前缀后缀返回页面,@Controller返回的字符串只是页面的名称,比如返回index,那么就会返回一个index.jsp或者index.html的页面
@RestController组合注解,@ResponseBody+@Controller 返回json 而不是页面
如果你想给前端返回一个字符串,就用@RestController
12.从没有用过@PathVariable
从路径取值接受参数
@RequestMaping(value="/test/{str}")
public String test(@PathVariable String str){}
13.一个方法可以有多个接口名
@RequastMappint(value={"/test1","/test2"})
public String test(){}
注意:虽然他们都注解了test这个方法,如果你拦截器里只拦截/test1接口,当他访问/test2接口时是不走你得拦截器的
14.全局异常处理
@ControllerAdvice+@ExceptionHandler
就近原则>@ControllerAdvice
踩过的一个坑:我访问被@RequestMapping注解的方法抛异常后,没有进如下断点
@ControllerAdvice(basePackageClasses = BREConfig.class)
@Slf4j
@Order(1)
public class AdviceTest {
@ExceptionHandler(Exception.class)
@ResponseBody
public String testException(Exception e){
log.info("测试advice");
return "";
}
}
原因,在BREConfig类中,已经存在被@ExceptionHandler注解的方法,优先走同一个类中的拦截
之后,我把同一个类的@ExceptionHandler注解去掉,断点果然进入到@ControllerAdvice类中
@ControllerAdvice只在springMvc中生效,然后springboot是基于springmvc的,所以生效,但是如果在sofaboot中,如果还访问被@RequestMapping注解的方法,可以生效,如果是通过rest,bolt访问,就不生效了,我理解是
15.starter,被别人引用的jar包
关键点:spring.factories
如何配置:
1.文件位置:resource下建立META-INF文件夹
2.内容:\换行符,多个时用半角逗号分割
用处:扫描@Configuration
如果在引用者的启动类中配置扫描路径中包括该@Configuration的类,也可以不配置spring.factories,但是作为公共starter,不应该这样耦合,为了解耦
如何扫描:核心注解@SpringBootApplication中有关于SpringFactoriesLoader的配置,会扫描所有spring.factories
16.application.yml优先级
jar包外部>jar包内部,application-{profile}.yml>application.yml,
互补配置,并且当优先级高的配置会覆盖优先级低的配置
使用apollo的情况下,apollo的优先级更大