1、什么是注解
1.1、注解是作用
增加可读性,向编译器、虚拟机做解释
1.2、元注解
元注解即用来描述注解的注解
- Retention: 这个元注解表示一个注解会被保留到什么时候,比如以下代码表示Developer注解会被保留到运行时
- Documented : 注解被@Documented元注解所修饰时,那么无论在哪里使用这个注解,会被Javadoc工具文档化。
- Inherited: 表明被修饰的注解类型是自动继承的。如果你想让一个类和它的子类都包含某个注解,就可以使 用@Inherited来修饰这个注解
- target: 这个元注解说明了被修饰的注解的应用范围,也就是被修饰的注解可以用来注解哪些程序元素,
1.3、常见的内建注解
-
@Override:
这个注解可以用来修饰方法,并且它只在编译时有效,在编译后的class文件中便不再存在那就是告诉编译器被修饰的方法是重写的父类中的相同签名的方法,编译器会对此做出检查,若发现父类中不存在这个方法或是存在的方法签名不同,则会报错。 -
@Deprecated: 它会被文档化,能够保留到运行时,能够修饰构造方法、属性、局部变量、方法、包、参数、类型这个注解的作用是说明被修饰的程序元素已被“废弃”,不再建议用户使用。
-
@SuppressWarnings:
它能够修饰的程序元素包括类型、属性、方法、参数、构造器、局部变量,只能存活在源码时,取值为String[]。它的作用是告诉编译器忽略指定的警告信息
1.4、自定义注解:
-
注解类型是通过”@interface“关键字定义的
-
所有的方法均没有方法体且只允许public和abstract这两种修饰符号
-
原始数据类型, String, Class, 枚举类型, 注解和它们的一维数组
2、Spring常用注解
2.1 @Configuration
@Configuration:配置类作用是配置Spring容器,也即 JavaConfig 形式的 Spring IoC 容器的配置类所使用。@Configuration核心是@Component,相当于传统的xml配置文件,如果有些第三方库需要用到xml文件,建议仍然 通过@Configuration类作为项目的配置主类——可以使用@ImportResource注解加载xml配置 文件。
测试示例:
- 注解方式
@Configuration
public class MyConfiguration {
@Bean
public MyBean myBean(){
System.out.println("myBean Initialized");
return new MyBean();
}
}
public class MyBean {
public MyBean(){
System.out.println("generate MyBean Instance");
}
public void init(){
System.out.println("MyBean Resources Initialized");
}
}
public class SpringConfigurationApplication {
public static void main(String[] args) {
//AnnotationConfigApplicationContext context = = new //AnnotationConfigApplicationContext(MyConfiguration.class)
// 因为我们加载的@Configuration 是基于注解形式的,所以需要创建AnnotationConfigApplicationContext
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
// 注册MyConfiguration 类并刷新bean 容器。
context.register(MyConfiguration.class);
context.refresh();
}
}
- xml配置
application-context.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd"
>
<!-- 相当于基于注解的启动类 AnnotationConfigApplicationContext-->
<context:annotation-config />
<bean class="com.spring.configuration.config.MyConfiguration"/>
</beans>
public class SpringConfigurationApplication {
public static void main(String[] args) {
ApplicationContext context =
new ClassPathXmlApplicationContext("applicationContext.xml");
}
}
2.2 @Condition
条件装配:通过配合基于条件的配置能力或定制化加载顺序,对自动化配置进行更加细粒度的调整和 控制。
自定义条件装配:
1、实现Condition.matches()方法;
2、matches()方法,条件满足成功返回true
3、条件不满足返回false
4、封装注解,并组合注解@Condition(class)@Conditional 注解表示在满足某种条件后才初始化一个 bean 或者启用某些配置。 它一般用在由 @Component、@Service、@Configuration 等注解标识的类上面,或者由 @Bean 标记的方法上。
示例:
如果一个 @Configuration 类标记了 @Conditional,则该类中所有标识了 @Bean 的方法 和 @Import 注解导入的相关类将遵从这些条件。
2.3 @ComponentScan
自动扫描包配置,默认一下注解的Bean可以被扫描:
- @Configuration 使用@Component 进行原注解,因此@Configuration 类也可以被组件扫描到(特别是使用XML元素)
- @Controller: 表明一个注解的类是一个"Controller",也就是控制器,可以把它理解为MVC 模式的Controller 这个角色。这个注解是一个特殊的@Component,允许实现类通过类路径的扫描扫描到。它通常与@RequestMapping 注解一起使用。
- @Service: 表明这个带注解的类是一个"Service",也就是服务层,可以把它理解为MVC 模式中的Service层这个角色,这个注解也是一个特殊的@Component,允许实现类通过类路径的扫描扫描到
- @Repository: 表明这个注解的类是一个"Repository",团队实现了JavaEE 模式中像是作为"Data Access Object" 可能作为DAO来使用,当与 PersistenceExceptionTranslationPostProcessor 结合使用时,这样注释的类有资格获得Spring转换的目的。这个注解也是@Component 的一个特殊实现,允许实现类能够被自动扫描到
-@Component: 表明这个注释的类是一个组件,当使用基于注释的配置和类路径扫描时,这些类被视为自动检测的候选者。
@Component
public class UserBean {}
@Configuration
public class UserConfiguration {}
@Controller
public class UserController {}
@Repository
public class UserDao {}
@Service
public class UserService {}
在MyConfiguration上加上@ComponentScan 注解,扫描上面5个类所在的包位置。代码如下:
@Configuration
@ComponentScan(basePackages = "com.spring.configuration.pojo")
public class MyConfiguration {
@Bean
public MyBean myBean(){
System.out.println("myBean Initialized");
return new MyBean();
}
}
public class SpringConfigurationApplication {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(MyConfiguration.class);
context.refresh();
// 获取启动过程中的bean 定义的名称
for(String str : context.getBeanDefinitionNames()){
System.out.println("str = " + str);
}
context.close();
}
}
- 自定义注解自动配置
1、自定义的注解上注解@Component。
2、@ComponentScan(includeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {xxx.class} ,useDefaultFilters = false))
3、自定义过滤器,实现TypeFilter接口
2.4 @Environment与PropertySource
-
Environment
JDK环境,Servlet环境,Spring环境等等;每个环境都有自己的配置数据,如System.getProperties()、System.getenv()等可以拿到JVM环境变量及操作系统环境变量;ServletContext.getInitParamete r()可以拿到Servlet环境配置数据等等;也就是说Spring抽象了一个Environment来表示环境配置
-
PropertySource
属性源,PropertySource代表了一个包含键值对的数据源。从类定义 上看,有一个表示属性源名字的name字段,还有一个表示具体属性源 泛型T的source字段。而属性源的设置则是通过构造方法传入的,同 时方法提供了通过键名获取键值的抽象方法getProperty
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = EnvironmentConfig.class)
@Configuration
@PropertySource("classpath:beanName.properties")
public class EnvironmentConfig {
@Autowired
Environment env;
@Test
public void testReadProperty(){
// 获取bean.name.controller 的属性
System.out.println(env.getProperty("bean.name.controller"));
// 判断是否包含bean.name.component
System.out.println(env.containsProperty("bean.name.component"));
// 返回与给定键关联的属性值
System.out.println(env.getRequiredProperty("bean.name.service"));
}
}
在/resources 目录下新建beanName.properties 文件,如下:
bean.name.configuration=beanNameConfiguration
bean.name.controller=beanNameController
bean.name.service=beanNameService
bean.name.component=beanNameComponent
bean.name.repository=beanNameRepository
- @Value 获取配置值
@ConfigurationProperties与@EnableConfigurationProperties:
application.properties 文件中新建配置 项,然后在 bean 中使用 @Value 注解来获取配置的值。
@EnableConfigurationProperties 注 解 表 示 对 @ConfigurationProperties 的 内 嵌 支 持 , 默 认 会 将 对 应 Properties Class 作 为 bean 注 入 的 IOC 容 器 中 , 即 在 相 应 的 Properties 类上不用加 @Component 注解。
2.5 @Import
@Import的定义(来自于JavaDoc):表明一个或者多个配置类需要导入,提供与Spring XML中相等的功能,允许导入@Configuration 、@ImportSelector、@ImportBeanDefinitionRegistar的实现,以及常规组件类似于AnnotationConfigApplicationContext。可能用于类级别或者是原注解。如果XML或者其他非@Configuration标记的Bean资源需要被导入的话,使用@ImportResource。
- 导入带有@Configuration的配置类: 容器中就会自动注册这个组件,id默认是全 类名
- 导入实现ImportSelector接口或子接口DeferredImportSelector的类:返回需要导入的组件的全类名数组;
- ImportBeanDefinitionRegistrar:手动注册bean到容器中。应用:Mybatis的 @MapperScan就是利用Registrar扫描 mapper
处理时机顺序: @Configuration>ImportSelector> ImportBeanDefinitionRegistrar
@Configuration
public class CustomerBo {
public void printMsg(String msg){
System.out.println("CustomerBo : " + msg);
}
@Bean
public CustomerBo testCustomerBo(){
return new CustomerBo();
}
}
@Configuration
public class SchedulerBo {
public void printMsg(String msg){
System.out.println("SchedulerBo : " + msg);
}
@Bean
public SchedulerBo testSchedulerBo(){
return new SchedulerBo();
}
}
@Configuration
@Import(value = {CustomerBo.class,SchedulerBo.class})
public class AppConfig {}
在config 包下新建一个ImportWithConfiguration ,用于测试@Import 和 @Configuration 的使用
public class ImportWithConfiguration {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
CustomerBo customerBo = (CustomerBo) context.getBean("testCustomerBo");
customerBo.printMsg("System out println('get from customerBo')");
SchedulerBo schedulerBo = (SchedulerBo) context.getBean("testSchedulerBo");
schedulerBo.printMsg("System out println('get from schedulerBo')");
}
}
- ImportSelector
1、ImportSelector:返回需要导入的组件的全类名数组
2、延迟导入DeferredImportSelector:是ImportSelector的拓展,同样返回需要导入的组件的 全类名数组。区别在于:处理时机不同
ImportSelector作用:
1)可导入无法扫描到的配置类
2)可做成开关控制是否导入配置类(模块注 解)
延迟作用:
1)对于导入的配置类是有条件注解 @Conditionalxxx有明显的作用
2)延迟导入支持执行类的Order、自动装配 顺序排序执行
- @ImportResource
这个注解提供了与@Import 功能相似作用,通常与@Configuration 一起使用,通过AnnotationConfigApplicationContext 进行启动,
public class TestService {
public TestService(){
System.out.println("test @importResource success");
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd"
>
<bean id = "testService" class="com.spring.configuration.config.TestService" />
</beans>
@Configuration
@ImportResource("classpath:importResources.xml")
public class ImportResourceWithConfiguration {
@Autowired
private TestService service;
public void getImportResource(){
new TestService();
}
public static void main(String[] args) {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(ImportResourceWithConfiguration.class);
context.getBean("testService");
}
}
3、其他
3.1 @Profile
表示当一个或多个@Value 指定的配置文件处于可用状态时,组件符合注册条件,可以进行注册。
1、作为类级别的注释在任意类或者直接与@Component 进行关联,包括@Configuration 类
2、作为原注解,可以自定义注解
3、作为方法的注解作用在任何方法
如果一个配置类使用了Profile 标签或者@Profile 作用在任何类中都必须进行启用才会生效,如果@Profile({“p1”,"!p2"}) 标识两个属性,那么p1 是启用状态 而p2 是非启用状态的。
3.2 @Lazy 延迟初始化
表明一个bean是否延迟加载,可以作用在方法上,表示这个方法被延迟加载;
可以作用在@Component (或者由@Component 作为原注解) 注释的类上,
表明这个类中所有的bean 都被延迟加载。如果没有@Lazy注释,或者@Lazy 被设置为false,那么该bean 就会急切渴望被加载;
@Lazy 还可以作用在@Autowired和@Inject注释的属性上,在这种情况下,
它将为该字段创建一个惰性代理,作为使用ObjectFactory或Provider的默认方法。
@Lazy
@Configuration
@ComponentScan(basePackages = "com.spring.configuration.pojo")
public class MyConfiguration {
@Bean
public MyBean myBean(){
System.out.println("myBean Initialized");
return new MyBean();
}
@Bean
public MyBean IfLazyInit(){
System.out.println("initialized");
return new MyBean();
}
}
public class SpringConfigurationApplication {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyConfiguration.class);
// 获取启动过程中的bean 定义的名称
for(String str : context.getBeanDefinitionNames()){
System.out.println("str = " + str);
}
}
}
3.3 @RunWith
一般用@RunWith 和 @Configuration 进行单元测试,这是软件开发过程中非常必要而且具有专业性的一部分,上面EnvironmentConfig 类证实了这一点:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = EnvironmentConfig.class)
@Configuration
@PropertySource("classpath:beanName.properties")
public class EnvironmentConfig {
@Inject
Environment env;
@Test
public void testReadProperty(){
// 获取bean.name.controller 的属性
System.out.println(env.getProperty("bean.name.controller"));
// 判断是否包含bean.name.component
System.out.println(env.containsProperty("bean.name.component"));
// 返回与给定键关联的属性值
System.out.println(env.getRequiredProperty("bean.name.service"));
}
}
3.4 其他
-
@Inject: 这是jsr330 的规范,通过AutowiredAnnotationBeanPostProcessor 类实现的依赖注入。位于javax.inject包内,是Java自带的注解。
@Inject
@Named(“environment”)
Environment env;
注:不加@Named注解,需要配置与变量名一致即可。 -
@Autowired: @Autowired 是Spring提供的注解,通过AutowiredAnnotationBeanPostProessor 类实现注入。位于org.springframework.beans.factory.annotation包内,是Spring 中的注解
@Autowired
Environment env;
默认是通过byType 实现注入 -
@Resource: @Resource 是jsr250规范的实现,@Resource通过CommonAnnotationBeanPostProcessor 类实现注入。@Resource 一般会指定一个name属性,如下:
@Resource(name = “environment”)
Environment env;
默认是通过byName 实现注入