SpringBoot2.0深度实践学习笔记(一)之Spring模式注解

springboot的自动装配源于SpringFramework的手动装备,SpringFramework手动装配来看起。

手动装配是按照SpringFramework的版本进行管理的,前提差不多都是基于基于注解驱动。

【什么是Spring模式注解】
一种用于声明在应用中扮演“组件”角色的注解
这里的应用:在Spring或者SpringBoot应用
组件:例如:@Component spring2.5,@Service:服务类注解 spring2.5,@Configuration 配置注解spring3

github上定义:A stereotype annotation is an annotation that is used to declare the role that a component plays within the application.
github关于模式注解(Stereotype Annotations)的解释中最为重要的一点就是:
凡是被 @Component 元标注(meta-annotated)的注解,如 @Service ,@Repository等,当任何组件标注它时,也被视作组件扫描的候选对象,可以理解为组件 是包括@Component及他的所有“派生”。

常用的模式注解
@Repository 数据仓储模式注解 起始版本2.0
@Component 通用组件模式注解 起始版本 2.5
@Service 服务模式注解 起始版本2.5
@Controller 控制器模式注解 起始版本2.5
@Configuration 配置类模式注解 起始版本 3.0

【装配的方式有2种】

1)xml方式:<context:component-scan> spring2.5提出的方案

base-package指明的这个包下所有的组件都会被扫描到

<meta charset="utf-8">

<?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"

xsi:schemaLocation="http://www.springframework.org/schema/beans

[http://www.springframework.org/schema/beans/spring-beans.xsd](http://www.springframework.org/schema/beans/spring-beans.xsd)

http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-

context.xsd">

<!-- 激活注解驱动特性 -->

<context:annotation-config />

<!-- 找寻被 @Component 或者其派生 Annotation 标记的类(Class),将它们注册为 Spring Bean  -->

<context:component-scan base-package="com.imooc.dive.in.spring.boot" />

</beans>

2)注解方式:@ComponentScan ,是spring3.1的方案

springboot1.0是基于spring4进行开发。
@ComponentScan(basePackages = "com.imooc.dive.in.spring.boot")
public class SpringConfiguration {
...
}

【Spring Framework手动装配自定义模式注解】
自定义模式注解,有两个性质@Component “派生性”和@Component “层次性”,我们从一个小栗子来看看这2个性质的体现

【@Component “派生性”】
注意这里的派生不是真正的派生就是一种理解

【栗子】
新建一个工程,工程下新建一个包annotation ,这个包下新建一个注解类FirstLevelRepository,作为一级仓储

/**
 * 一级 {@link Repository @Repository}
 */
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Repository // 数据仓储模式注解
public @interface FirstLevelRepository {

    String value() default "";

}

备注:
@Repository // 数据仓储模式注解
通过源码可以看到@Repository元标注的是@Component,
并且,他们的签名都保持这一致,属性方法value()
这就是所谓的“派生性”

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Repository {
    @AliasFor(
        annotation = Component.class
    )
    String value() default "";  //签名 一致性 :属性方法value
}


@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Indexed
public @interface Component {
    String value() default "";
}

接下来,我们要将这个注解作用到一个类上面
新建一个包repository,下面新建一个类MyFirstLevelRepository,类上面添加我们刚才自定义的注解,通过value来添加一个bean的名称,注意名字的第一个字母要小写,在进行组件扫描后MyFirstLevelRepository这个类就成为一个bean。

/**
 * 我的{@link FirstLevelRepository}
 */
@FirstLevelRepository(value = "myFirstLevelRepository")   //Bean的名字
public class MyFirstLevelRepository {
}

我们新建一个bootstrap包,下面建一个引导类,就是启动类RepositoryBootstrap,这里我们不使用注解@SpringBootApplication来标注引导类,我们采用SpringApplicationBuilder()spring2.0写法。
可以指定类型web,我们定义为非web类型 ,一个普通类型,注解驱动

/**
 * 仓储引导类
 */
@ComponentScan(basePackages = "com.cbt.diveinspringboot.repository")
public class RepositoryBootstrap {
    public static void main(String[] args) {
        ConfigurableApplicationContext context = new SpringApplicationBuilder(RepositoryBootstrap.class)
                .web(WebApplicationType.NONE)
                .run(args);

        // myFirstLevelRepository Bean是否存在
        MyFirstLevelRepository myFirstLevelRepository = context.getBean("myFirstLevelRepository",MyFirstLevelRepository.class);

        System.out.println("myFirstLevelRepository Bean:" + myFirstLevelRepository);

        context.close();
    }
}

说明
1、run()返回的对象 ConfigurableApplicationContext
2、关闭上下文context
3、扫描MyFirstLevelRepository 这个类的方式:
1)可以包MyFirstLevelRepository这个bean丢进去
2)也可以把RepositoryBootstrap 这个bean丢进去
4、这里先采用注解@ComponentScan 的装配方式,这个@FirstLevelRepository组件可以用来识别我们的MyFirstLevelRepository类。
通过@ComponentScan 扫描包下所有的类,
类被@FirstLevelRepository标记的就会被认为是一个bean,我们可以通过Bean的名称进行获取。
通过上下文对象去获取到bean,第一个参数是bean的名称,就是通过类上的注解value获取的,第二个参数bean的类型,这种方式不用进行类型强转的

运行引导类:结果显示进行组件扫描后MyFirstLevelRepository这个类就成为一个bean了。


1.png

如果你采用@Component注解来替换我们自定义的注解@ FirstLevelRepository结果是一样的 ,你可以自己运行看看 ----这就是所谓的“派生性”
可以一直注解上去

@Component(value = "myFirstLevelRepository")
public class MyFirstLevelRepository {
}

【@Component “层次性”】就是自定义的注解还可以用来标注在其他自定义的注解上面
在annotation包下新建注解SecondLevelRepository
签名要保持一致

/**
 * 二级{@link Repository }
 */
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@FirstLevelRepository  //标注自定义注解
public @interface SecondLevelRepository {
    String value() default "";
}

将这个@SecondLevelRepository注解添加到MyFirstLevelRepository类

/**
 * 我的{@link SecondLevelRepository}
 */
@SecondLevelRepository(value = "myFirstLevelRepository")
public class MyFirstLevelRepository {
}

层次关系:

  1. @Component
    2.@Repository
    3.@FirstLevelRepository
    4.@SecondLevelRepository

运行引导类:结果和上面是一样的。

我们可以再看一个栗子:
注解:@SpringBootApplication

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
    excludeFilters = {@Filter(
    type = FilterType.CUSTOM,
    classes = {TypeExcludeFilter.class}
), @Filter(
    type = FilterType.CUSTOM,
    classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {

看一下里面的:@SpringBootConfiguration这个注解,这个注解标注@Configuration

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {

}

@Configuration注解又元标注了@Component

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration {
    @AliasFor(
        annotation = Component.class
    )
    String value() default "";
}

说明@SpringBootApplication也是属于模式注解

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容