java基础注解
@FunctionallInterface
高阶函数:如果一个函数接收一个函数作为参数,或者返回一个函数作为返回值,那么该函数就叫做高阶函数。函数式编程语言js等语言里面都支持大量的高阶函数,JAVA从1.8开始也开始支持高阶函数。
此接口作用与只有一个抽象方法的接口上(接口是抽象类的变体),但是接口并不继承Object类
//TODO
在
@link
使用一场景:当某些方法被@Deprecated注解并有替换方法,可以在替换方法上使用,语法如下
/**
*@Deprecated in favor of
{link #copy_reference}//替换方法的全reference
*
*/
@Deprecated
public void xxx();//被替换方法
public void substrute_xxx();
这样其他程序员在使用过时方法的时候,就可以通过idea发现替换方法。
@see
//TODO
Rest 相关注解
Rest相关的注解如下
@QueryParam @BeanParam @PathParam @ApplicationParam
springframework注解
pring框架功能很强大,但是就算是一个很简单的项目,我们也要配置很多东西。因此就有了Spring Boot框架,它的作用很简单,就是帮我们自动配置。Spring Boot框架的核心就是自动配置,只要存在相应的jar包,Spring就帮我们自动配置。如果默认配置不能满足需求,我们还可以替换掉自动配置类,使用我们自己的配置。另外,Spring Boot还集成了嵌入式的Web服务器,系统监控等很多有用的功能,让我们快速构建企业及应用程序。
Springboot的注解包括多种注解
@RequestBody
@Bean,@Component,@Controller,@Service, @Repository,
@Configuration,@EnableAutoConfiguration,@ComponentScan,@SpringbootApplicatiion
@ResponseBody,@RestController
@Import,@ImportResource,@Resource,@Qualifier
@AutoWired,@Value,@Inject,@Autowired,@Scope,@PostConstruct,@PreDestory
@RunWith,@SpringBootTest,@ConfigurationProperties,@PropertySource,@ContextConfiguration
1 Bean注解详解
@Bean是一个方法级别的注解,主要用在@Configuration注解的类中,也可以用在@Component注解的类中,添加的bean的id默认为方法名。
@Configuration
public class AppConfig {
@Bean
public TransferService transferService() {
return new TransferServiceImpl();
}
}
这个配置就等同于之前在xml里的配置
<beans>
<bean id="transferService" class="com.acme.TransferServiceImpl"/>
</beans>
bean的依赖
@bean 也可以依赖其他任意数量的bean,如果TransferService 依赖 AccountRepository,我们可以通过方法参数实现这个依赖
@Configuration
public class AppConfig {
@Bean
public TransferService transferService(AccountRepository accountRepository) {
return new TransferServiceImpl(accountRepository);
}
}
@PostConstruct, @PreDestory
接受生命周期的回调
@PostConstruct说明
被@PostConstruct修饰的方法会在服务器加载Servlet的时候运行,并且只会被服务器调用一次,类似于Servlet的inti()方法。被@PostConstruct修饰的方法会在构造函数之后,init()方法之前运行。
执行顺序
@ PostConstruct注释用于在完成依赖项注入以执行任何初始化之后需要执行的方法。必须在类投入使用之前调用此方法。 所有支持依赖注入的类都必须支持此注释。即使类没有请求注入任何资源,也必须调用使用PostConstruct注释的方法。 只有一个方法可以使用此批注进行批注。 应用PostConstruct注释的方法必须满足以下所有条件:除了拦截器之外,方法绝不能有任何参数,在这种情况下它采用Interceptor规范定义的InvocationContext对象。 在拦截器类上定义的方法必须具有以下签名之一: void <METHOD>(InvocationContext)Object <METHOD>(InvocationContext)抛出异常注意: PostConstruct拦截器方法不能抛出应用程序异常,但可以声明它抛出检查异常,包括java.lang.Exception, 如果相同的拦截器方法除了生命周期事件之外插入业务或超时方法。 如果PostConstruct拦截器方法返回一个值,容器将忽略它。 在非拦截器类上定义的方法必须具有以下签名:void <METHOD>()应用PostConstruct的方法可以是public,protected,package private或private。 除应用程序客户端外,该方法绝不能是静态的。 该方法可能是最终的。如果该方法抛出一个未经检查的异常,那么该类绝不能投入使用,除非EJB可以处理异常甚至从它们恢复的EJB 然后就会思考问题,这个注释是修饰初始化之后需要执行的方法,那么它和@Autowired、构造函数的执行顺序是什么呢?(当然注释中已经说明了PostConstruct注释用于在完成依赖项注入之后)
@Service
public class BeanA {
@Autowired
private BeanB beanB;
public BeanA() {
System.out.println("这是Bean A 的构造方法");
}
@PostConstruct
private void init() {
System.out.println("这是BeanA的 init 方法");
beanB.testB();
}
}
@Service
public class BeanB {
@PostConstruct
private void init() {
System.out.println("这是BeanB 的init 方法");
}
public BeanB() {
System.out.println("这是Bean B的 构造方法");
}
void testB() {
System.out.println("这是Bean B 的 testB 方法");
}
}
启动后输出:
这是Bean A 的构造方法
这是Bean B的 构造方法
这是BeanB 的init 方法
这是BeanA的 init 方法
这是Bean B 的 testB 方法
所以得到结论: 构造方法 > @Autowired > @PostConstruct
@PreConstruct说明
被@PreConstruct修饰的方法会在服务器卸载Servlet的时候运行,并且只会被服务器调用一次,类似于Servlet的destroy()方法。被@PreConstruct修饰的方法会在destroy()方法之后运行,在Servlet被彻底卸载之前。
任何使用@Bean定义的bean,也可以执行生命周期的回调函数,类似@PostConstruct and @PreDestroy的方法。用法如下
public class Foo {
public void init() {
// initialization logic
}
}
public class Bar {
public void cleanup() {
// destruction logic
}
}
@Configuration
public class AppConfig {
@Bean(initMethod = "init")
public Foo foo() {
return new Foo();
}
@Bean(destroyMethod = "cleanup")
public Bar bar() {
return new Bar();
}
}
默认使用javaConfig配置的bean,如果存在close或者shutdown方法,则在bean销毁时会自动执行该方法,如果你不想执行该方法,则添加@Bean(destroyMethod="")来防止出发销毁方法
指定bean的scope,使用@Scope注解
你能够使用@Scope注解来指定使用@Bean定义的bean
@Configuration
public class MyConfiguration {
@Bean
@Scope("prototype")
public Encryptor encryptor() {
// ...
}
bean的别名,默认情况下bean的名称和方法名称相同,你也可以使用name属性来指定
@Configuration
public class AppConfig {
@Bean(name = "myFoo")
public Foo foo() {
return new Foo();
}
}
bean的命名支持别名,使用方法如下
@Configuration
public class AppConfig {
@Bean(name = { "dataSource", "subsystemA-dataSource", "subsystemB-dataSource" })
public DataSource dataSource() {
// instantiate, configure and return DataSource bean...
}
}
bean的描述
有时候提供bean的详细信息也是很有用的,bean的描述可以使用 @Description来提供
@Configuration
public class AppConfig {
@Bean
@Description("Provides a basic example of a bean")
public Foo foo() {
return new Foo();
}
}
@Resource注解
@Component详解
Component是一个元注解,意味着他可以注解其他类注解,如@Controller,@Service, @Repository以及@Aspect, 官方的原话是:带此注解的类看为组件,当使用基于注解的配置和类路径扫描的时候,这些类就会被实例化。其他类级别的注解也可以被认定为是一种特殊类型的组件,比如@Repository @Aspect。所以,@Component可以注解其他类注解。
Component名称
a.不指定bean的名称,默认为类名首字母小写university
@Component
public class University {
to do sthing...
}
获取bean方式:
ApplicationContext ctx = new ClassPathXmlApplicationContext("./config/application Context.xml");
University ust = (University) ctx.getBean("university");
b.指定bean的名称
@Component("university1")
public class University {
to do sthing...
}
获取bean方式:
ApplicationContext ctx = new ClassPathXmlApplicationContext("./config/applicationContext. xml");
University ust = (University) ctx.getBean("university1");
@Component和@Bean的区别
众所周知,@Component注解是在Spring 2.5版本引入的,以便于可以通过路径扫描的方式来替换配置文件。@Bean是在Spring3.0版本引入的,可以配合使用@Configuration注解来达到完全替换配置文件的目的。同时@Bean是一个方法注解,而@Component是一个类注解。@Component和@Bean做两个完全不同的事情,不应该混为一谈。
在 @Component 注解的类中不能定义(类内依赖@Bean注解的)这种方法。@Configuration可以。
Spring帮助我们管理Bean分为两个部分,一个是注册Bean,一个装配Bean。
完成这两个动作有三种方式,一种是使用自动配置的方式、一种是使用JavaConfig的方式,一种就是使用XML配置的方式。
在自动配置的方式中,使用@Component去告诉Spring,我是一个bean,你要来管理我,然后使用@AutoWired注解去装配Bean(所谓装配,就是管理对象直接的协作关系)。然后在JavaConfig中,@Configuration其实就是告诉spring,spring容器要怎么配置(怎么去注册bean,怎么去处理bean之间的关系(装配))。那么久很好理解了,@Bean的意思就是,我要获取这个bean的时候,你spring要按照这种方式去帮我获取到这个bean。到了使用xml的方式,也是如此。君不见<bean>标签就是告诉spring怎么获取这个bean,各种<ref>就是手动的配置bean之间的关系。
@Configuration
@Configuration注解一般注解在类里面有@Value注解的成员变量或@Bean注解的方法,@Bean主要和@Configuration配合使用的。@Configuration注解本质上还是一个@Compoent,因此<context:component-scan/>或者@ComponenScan都能处理@Configuration注解的类
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration {
String value() default "";
}
可以看到在@Configuration注解中是包含@Component注解的,被@Configuration修饰的类被定义为一个Spring容器(应用上下文)
@Configuration就相当于Spring配置文件中的<beans />标签,里面可以配置bean。
@Configuration标注的类必须符合下面所有要求:
- 配置类必须以类的形式提供(不能是工厂方法返回的实例),允许通过生成子类在运行时增强(cglib 动态代理)。
- 配置类不能是 final 类(没法动态代理)。
- 配置注解通常为了通过 @Bean 注解生成 Spring 容器管理的类。
- 配置类必须是非本地的(即不能在方法中声明,不能是 private)。
- 任何嵌套配置类都必须声明为static。
- @Bean方法不能创建进一步的配置类(也就是返回的bean如果带有@Configuration,也不会被特殊处理,只会作为普通的 bean)。
Spring 容器在启动时,会加载默认的一些PostPRocessor,其中就有 ConfigurationClassPostProcessor,这个后置处理程序专门处理带有@Configuration注解的类,这个程序会在bean定义加载完成后,在bean初始化前进行处理。其主要处理的过程就是使用 cglib 动态代理对类进行增强,使用增强后的类替换了beanFactory原有的 beanClass,增强类会对其中带有@Bean注解的方法进行额外处理,确保调用带@Bean注解的方法返回的都是同一个实例。
但是对于@Component,@Component 注解并没有通过cglib来代理@Bean方法的调用,因此调用带@Bean注解的方法态返回的都是新的实例。
读取配置文件
一般我们配置配置文件都是多套的,测试环境test,生产环境prod,开发环境dev,xx环境stage,不同的环境下某些参数是不一样的,因而配置文件也会不一样的。
注意配置文件命名规范:application-xxx.yml因为项目默认加载配置文件时会有这个格式要求:1springboot默认使用一个全局的配置文件,配置文件名是固定的,配置文件有两种(开头都是application,主要是文件的后缀):Application.properties和application.yml
配置完文件放在src/main/resource目录或者类路径/config下
application.yml,application-dev.yml,application-test.yml,application-stage.yml文件
在application.yml配置文件中一般配置的都是公共的不用动的配置
Server:
Port:8090//不写则默认8080
Spring:
Profiles:
Active:stage
其他配置文件内容:
application-dev.yml:
spring:
profiles: dev
user:
userName: 王立国-dev
sex: 男
age: 18
author:
name: wlg-dev
height: 174
application-test.yml:
spring:
profiles: test
user:
userName: 王立国-test
sex: 男
age: 18
author:
name: wlg-test
height: 174
application-stage.yml:
spring:
profiles: stage
user:
userName: 王立国-stage
sex: 男
age: 18
author:
name: wlg-stage
height: 174
每个配置文件都说明了自己的spring.profiles名称,然后其他内容稍有不同以示区分。
读取配置文件的方式有两种:@PropertySouce和@ImportSource
@PropertySource
1、@PropertySource配置文件路径设置,加载指定的配置文件,在类上添加注解,如果在默认路径下可以不添加该注解。注意@PropertySource只能加载.properties文件而不能加载.yml文件
需要用@PropertySource的有:
- 例如非application.properties,classpath:config/my.properties指的是src/main/resources目录下config目录下的my.properties文件,
- 例如有多配置文件引用,若取两个配置文件中有相同属性名的值,则取值为最后一个配置文件中的值
- 在application.properties中的文件,直接使用@Value读取即可,applicarion的读取优先级最高
@PropertySource({"classpath:config/my.properties","classpath:config/config.properties"})
public class TestController
@ImportSource
@ImportResource:导入Spring的配置文件,让配置文件里面的内容生效;
Spring Boot里面没有Spring的配置文件,我们自己编写的配置文件,也不能自动识别;
想让Spring的配置文件生效,加载进来;@ImportResource标注在一个配置类上
@Import
在应用中,有时没有把某个类注入到IOC容器中,但在运用的时候需要获取该类对应的bean,此时就需要用到@Import注解,注意@Import只能使用在类上。
@Import 有三种使用方式
1,直接填写class数组
2,实现ImportSelector
3,ImportBeanDefinitionRegistrar方式
示例如下: 先创建两个类,不用注解注入到IOC容器中,在应用的时候在导入到当前容器中。
1、创建Dog和Cat类
package com.example.demo;
public class Dog { }
cat类
package com.example.demo;
public class Cat {}
2、在启动类中需要获取Dog和Cat对应的bean,需要用注解@Import注解把Dog和Cat的bean注入到当前容器中。
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Import;
//@SpringBootApplication
@ComponentScan
/*把用到的资源导入到当前容器中*/
@Import({Dog.class, Cat.class}) //这样就会把dog和cat实例放入到spring容器中
public class App {
public static void main(String[] args) throws Exception {
ConfigurableApplicationContext context = SpringApplication.run(App.class, args);
System.out.println(context.getBean(Dog.class));
System.out.println(context.getBean(Cat.class));
context.close();
}
}
3、运行该启动类,输出结果:
com.example.demo.Dog@4802796d
com.example.demo.Cat@34123d65
从输出结果知,@Import注解把用到的bean导入到了当前容器中。并且id为默认全类名,而@Bean只是类型
第二种
public class MyImportSelector implements ImportSelector{
@Override
public String[] selectImports(AnnotationMataData annotationMetaData){
//返回值: 就是我们实际上要导入到容器中的组件全类名【重点 】
//参数:AnnotationMetadata表示当前被@Import注解给标注的所有注解信息【不是重点】
//需要注意的是selectImports方法可以返回空数组但是不能返回null,否则会报空指针异常!
}
}
第三种,使用ImportBeanDefinitionRegister,只不过这种方法可以自定义注册
public class Myclass2 implements ImportBeanDefinitionRegistrar {
//该实现方法默认为空
public class Myclass2 implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata annotationMetadata,
BeanDefinitionRegistry beanDefinitionRegistry) {
//指定bean定义信息(包括bean的类型、作用域...)
RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(TestDemo4.class);
//注册一个bean指定bean名字(id)
beanDefinitionRegistry.registerBeanDefinition("TestDemo4444",rootBeanDefinition);
}
}
}
另外,也可以导入一个配置类
还是上面的Dog和Cat类,现在在一个配置类中进行配置bean,然后在需要的时候,只需要导入这个配置就可以了,最后输出结果相同。
MyConfig 配置类:
package com.example.demo;
import org.springframework.context.annotation.Bean;
public class MyConfig {
@Bean
public Dog getDog(){
return new Dog();
}
@Bean
public Cat getCat(){
return new Cat();
}
}
比如若在启动类中要获取Dog和Cat的bean,如下使用:
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Import;
//@SpringBootApplication
@ComponentScan
/*导入配置类就可以了*/
@Import(MyConfig.class)
public class App {
public static void main(String[] args) throws Exception {
ConfigurableApplicationContext context = SpringApplication.run(App.class, args);
System.out.println(context.getBean(Dog.class));
System.out.println(context.getBean(Cat.class));
context.close();
}
}
@Value详解
利用@Value获取值,在springboot中如果不配置@PropertySource(value="classpath:redis.properties")(配置文件路径),默认是从application.properties中获取值,你也可以配置额外的@PropertySource,如下:
@Value("${my.name}")
private String myName;
3、实例
我在application-test.properties里面加上属性wechat.pay.url
@Primary
配置在某个接口有多个实现类的某个实现类上,在其他Bean中使用@Autowired注入该接口类型的bean时,优先注入这个实现类的bean。和@Component一起使用,否则无效。
@ConfigurationProperties
为springboot 专用的属性注入属性 ,文件名必须是application.properties/applicaiton.yml 默认为全局文件中获取这些属性值 。@ConfigurationProperties告诉spring波特将本类中的所有属性和配置文件中相关的配置进行绑定,prefix=”person”:配置文件中下面的的属性进行一一映射。
例如:
//将配置文件中的每一个属性的值映射到这个组件中
//告诉springboot将本类中的所有属性和配置文件中的相关配置进行绑定
//(prefix = "person")将配置文件中以person下的所有属性进行绑定
@Component
@ConfigurationProperties(prefix = "person")
public class Person {
private String name;
private Integer age;
private boolean boss;//布尔值
private Date bir;//时间
private Map<String,Object> map;//Map
private List<String> lists;//List
private Dog dog;//对象
}
public class Dog {
private String name;
private Integer age;
}
在yml配置文件中
person:
name: Mr
age: 14
boss: true
bir: 2018/12/21
map: {m1: v1,m2: v2}
lists:
- mc
- mt
dog:
name: dogdog
age: 10
使用properties后缀的:
person.name=mr
person.age=22
person.bir=2018/12/11
person.boss=true
person.map.q1=1
person.map.q2=2
person.lists=a,b,c
person.dog.name=cat
person.dog.age=22
@ComponentScan
@Component是标注哪个类被扫描进入spring IOC容器中,而@ComponentScan是表明采用何种策略去扫描装配bean。默认情况下,@ComponentScan只会扫描当前包和子包。
@Condition和@Conditional
@ConditionalOnBean(仅仅在当前上下文中存在某个对象时,才会实例化一个Bean)
@ConditionalOnClass(某个class位于类路径上,才会实例化一个Bean)
@ConditionalOnExpression(当表达式为true的时候,才会实例化一个Bean)
@ConditionalOnMissingBean(仅仅在当前上下文中不存在某个对象时,才会实例化一个Bean)
@ConditionalOnMissingClass(某个class类路径上不存在的时候,才会实例化一个Bean)
@ConditionalOnNotWebApplication(不是web应用)