Spring Framework 手动装配 笔记(一)

学习笔记是学习了 慕课网小马哥的 《Spring Boot 2.0深度实践之核心技术篇》根据自己的需要和理解做的笔记。

由于教学视频是由浅入深的,因此笔记也会一点一点深入。在学完第二章的时候看到了spring framework 的手动装配,特别想知道是如何进行注解驱动以及接口编程方式来声明Bean的,在自己debugger很久后,还是没有定位到准确位置。发现之后的视频有讲解,所以后期会有这方面的详细讲解,因为我也是对装配这十分感兴趣。

Spring Framework 手动装配

类似于@Enable 注解模块的装配

Spring Framework 3.1 开始支持”@Enable 模块驱动“。所谓“模块”是指具备相同领域的功能组件集合, 组合所形成一个独立
的单元。比如 Web MVC 模块、AspectJ代理模块、Caching(缓存)模块、JMX(Java 管 理扩展)模块、Async(异步处理)模块等。

实现方式(注解驱动、接口编程方式)

我会先总结驱动方式是如何声明的,再以自定义的例子来复习和巩固。

注解驱动方式

我们先来看一下 Spring framework 中的@EnableWebMvc 驱动注解的声明方式。

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(DelegatingWebMvcConfiguration.class)
public @interface EnableWebMvc {
}

我们可以看到,在简单不能在简单的注解生命中,只是多引入了 @import 注解,那么这个注解是干什么用的呢。我们点进注解看一下源码和解释 。

/**
* Indicates one or more {@link Configuration @Configuration} classes to import.
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Import {

   /**
    * {@link Configuration}, {@link ImportSelector}, {@link ImportBeanDefinitionRegistrar}
    * or regular component classes to import.
    */
   Class[] value();

}

我只截取了第一行解释,就是引入一个或多个 有 @Configuration 注解的类。其实这个类才是我们具体要做操作的驱动类。

因此 在 @EnableWebMvc 中 @Import 引入的 DelegatingWebMvcConfiguration 类 就是真正实现装配的类。

对于DelegatingWebMvcConfiguration 我也做了截取。

@Configuration
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {}

在这个类中, 我们必须要引入 @Configuration 注解 ,来让spring 容器识别他是一个配置组件。

这就是简单的注解驱动的实现。看起来没有多难,但是要是结合庞大的spring framework 体系,那真的是很难理解每个注解驱动 里签名方法的作用。

话不多说,让我们来自己实现一个简单的注解驱动,本例是按照小马哥视频中的例子演示的。

我们按照 @EnableWebMvc 模仿来实现。

1.创建一个 驱动注解 @EnableHelloWorld

/**
 * 基于注解实现的方式声明一个@Enable注解
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(HelloWorldConfiguration.class)
public @interface EnableHelloWorld {
}

我们可以看到除了注解名和 @Import 引入的类名不同 其他的都一样

2.创建一个 HelloWorldConfiguration 注解驱动实现类。

/**
 * @Configuration 注解的解释
 * Indicates that a class declares one or more {@link              org.springframework.context.annotation.Bean @Bean} methods and
 * may be processed by the Spring container to generate bean definitions and
 * service requests for those beans at runtime
 * 声明一个@EnableHelloWorld 注解的驱动
 */
@Configuration
public class HelloWorldConfiguration {

    @Bean
    public String helloWorld() {
        return "Hello World by HelloWorldConfiguration";
    }
} 

首先先标注 @Configuration 使spring 识别 HelloWorldConfiguration 是一个配置组件,然后声明一个bean ,需要用注解 @Bean标识 ,bean 的名字就是方法的名字,bean的类型是String 类型。

这样 简单的注解驱动就完成了。我们来使用spring-boot跑一下 看看效果。

3.引导类代码。

@EnableHelloWorld
public class EnableHelloWorldBootstrap {

    public static void main(String[] args) {
        ConfigurableApplicationContext context = new SpringApplicationBuilder(EnableHelloWorldBootstrap.class)
                .web(WebApplicationType.NONE)
                .run(args);

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

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

        // 关闭上下文
        context.close();
    }
}

首先我们需要注意的是 @EnableHelloWorld ,只有加了这个注解驱动,那么 spring 才会加载我们的自定义bean(helloWorld)。

我们来启动容器来跑一下程序,看看我们是否把 helloworld 这个bean 加到了容器中。

图1.PNG

我们看到,可以取到helloworld 这个bean。

Demo代码地址

接口编程方式

这种方式相比注解驱动更灵活一些,可以做一些逻辑操作。与注解驱动不同的是 @Import 中引入的是一个实现 ImportSelector 接口的类。而 ImportSelector中的 方法

@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
    return new String[0];
}

我们可以通过 importingClassMetadata 参数 来获取 注解属性等一系列操作,做一些逻辑处理。

下面也让我们来简单自定义实现一个 接口编程方式的装配。

1.创建一个 EnableHelloWorldServer 注解。

/**
 * 基于注解实现的方式声明一个@Enable注解
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(HelloWorldSelector.class)
public @interface EnableHelloWorldServer {
}

2.创建一个实现 ImportSelector 接口的类 HelloWorldSelector

/**
 * 注解接口编程的接口
 */
public class HelloWorldSelector implements ImportSelector {

    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        return new String[]{HelloWorldConfiguration.class.getName()};
    }
}

在这里 我们就简单返回 HelloWorldConfiguration,这样spring容器会找到HelloWorldConfiguration 并且将组件加载到容器中。

3.创建引导类。

@EnableHelloWorldServer
public class EnableHelloWorldBootstrap {

    public static void main(String[] args) {
        ConfigurableApplicationContext context = new SpringApplicationBuilder(EnableHelloWorldBootstrap.class)
                .web(WebApplicationType.NONE)
                .run(args);

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

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

        // 关闭上下文
        context.close();
    }
}

我们可以看出来,在引导类和实现上都是一样的,只是注释不一样,引用的装配方式就不一样。我们来运行一下看看效果。

图2.PNG

Demo代码

接口编程的方式 相比 注解驱动方式,多绕了一层,也就是这一层,让接口编程方式更灵活。

注解驱动: HelloWorldConfiguration -> HelloWorld

接口编程方式 HelloWorldSelector-> HelloWorldConfiguration -> HelloWorld

其实 无论是 注解驱动装配 还是接口编程方式装配,都是把 spring framework 的xml配置形式多样化。

你可能感兴趣的:(Spring Framework 手动装配 笔记(一))