Spring 注解驱动开发

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring 注解驱动开发相关的知识,希望对你有一定的参考价值。

参考技术A 1).

启用spring的类路径扫描功能, @Component\@Controller\@Service\@Repositroy 注解的bean类自动注册到Spring 容器.

可以使用Spring 的context 模式的<component-scan>元素来启动Spring的类路径扫描功能.

例如:<context:component-scan base-package = "sample-spring">

<component-scan>元素的<include-filter> 和 <exclude-filter>子元素提供了一种更为简洁的方法来指定用于自动注册的组件类,以及应忽略的类.

<include-filter> 和 <exclude-filter> 中的type 特性可以接受的可能值

annotation/assingable/aspect/regex/custom

2).@Autowired 注解通过类型"自动装配依赖项" ,可以在构造函数级,方法级和字段级使用.

spring的 AutowritedAnnotationBeanPostProcessor 对使用Spring 的@Autowried 或 JSR3.0 的@Inject 注解的字段, 方法和构造函数进行自动装配.

@Autowired 注解 构造方法, 则构造方法参数是自动装配的

@Autowired 注解 方法 ,则方法的参数是自动装配的.

@Autowried 的 required 特性可以指定一个依赖项是必选的还是可选的.如果将@Autowired 的required特性值设置为

false ,则该依赖项是可选的.默认情况下为true

Spring 的 @Qualifier 注解以及@Autowired 注解来按名称自动连接依赖项.@Qualifier 注解可以在字段级,方法参数级和构造参数级来按名称自动装配依赖项.

3). 自定义注解, 如下面的例子

@Target(ElementType.FIELD,ElementType.PARAMETER, ElementType.Type, ElementType.ANNOTATION_TYPE_)

@Retention(RetentionPolicy.RUNTYPE)

@Qualifier

public @interface FundTransfer

TransferMode  transferSpeed();

BankType bankType();



如果不使用@Qualifier 元注解, 则需要使用Spring的CustomerAutowrieConfiger(一个BeanFactoryPostProcessor)bean显示地向Spring 容器注册@FundTransfer 注解.

这里的@FundTransfer 与 Spring 的@Qualifier 注解具有相同的用途,它们允许基于transferSpeed和backType特性对bean进行自动装配.

如果没有@Qualifier 进行注解, 那么需要使用Spring 的CustomerAutowrieConfiger 向Spring 显示注册

<bean class= "org.springframework.beans.factory.annotation.CustomAutowrieConfiger">

<property name ="customQualifierTypes">

<set>

<value>sample.MyCustomeQualifer</value>

</set>

<property >

</bean>

4).JSR330的@Inject 和 @Named注解

JSR330 (Java 依赖注入) 将Java 平台依赖注入注解标准化 JSR330 分别定义恶劣Spring 的@Autowired 和@Qualifier

注解类似的@Inject 和@Named注解 Spring 提供对@Inject 和@Named 注解的支持.

  要使用@Name 和 @Inject 注解 ,引入jar 包文件

  <dependency>

<groupId>javax.inject</groupId>

<artifactId>javax.inject</artifactId>

<version>1</version>

  </dependency>

5).Java 8的Optional 类型

Spring 支持对Optional 类型的字段,构造函数参数和方法参数的自动装配.

6).JSR250的@Ressource 注解

Spring通过JSR250的@Resource 注解支持字段和setter 方法的名称自动装配. @Resource 注解由

CommonAnnotationBeanPostProcessor 处理, @Resource 注解的name 特性指定要自动装配的bean 名称.注意,不能使用

@Resource 注解来自动装配构造参数和接收多个参数的方法.

@Autowired 注解不适用于本身为集合或Map 类型的bean .

7).@Scope , @Lazy ,@DependsOn , @Primary 注解不适用于本身为集合

@Scope 指定bean的范围

@Lazy  指定该bean 由Spring 容器延迟创建

@DependsOn 指定bean的 隐式依赖项

@Primary 将bean 指定位为自动装配的主要候选项

@Scope注解接收一个value 特性来指定bean的范围, 例如, 将value 特性的值设置为prototype . 如果使用的是Spring4.2更高的版本,则可以使用scopeName 特性来取代value 特性.

@Lazy  默认情况下singleton 范围的 Spring bean 被即时初始化, 也就是在创建时Spring 容器时实例化它们.如果想要一个singleton 被延迟创建, 用@Lazy 注解一个 singleton bean的 bean 类.

@Lazy 注解的value 特性指定了bean 是延迟初始化还是即时初始化. 如果 value 特性的值为true , 则表示该bean已被延迟初始化.看下面这个例子如何实现 延迟自动装配

@Service

public class MyService

private static logger logger = logManager.getLogger(MyServices.class);

@Autowired

@Lazy

private StatelessService statelessService;

@Autowired

@Lazy

private StatefulService statefulService;  //是多例的

public void useStateless()

logger.info("-->"+statelessService);



public void useStateful()

logger.info("-->"+statefulService);





在上面的例子中 ,只有在使用statelessService 和 statefulService 时才会自动装配.

@DependsOn  可以使用@DependsOn 注解指定隐式bean 依赖项. 如下:

@DependsOn(Value = "beanA","beanB")

@Component

public class Sample.....

在上面的例子中 创建Sample 类的实例之前, Sample类的@DependsOn 注解指示Spring 容器创建beanA 和beanB

@Priary 如果多个自动装配候选项对于一个依赖项可用,@Primary 注解将一个bean 指定为自动装配的主要候选项.

7). @Value 注解  注解可以在字段级, 方法级, 方法参数级 和构造函数级使用.Spring 中处理@Autowired 和@Inject注解的AutowriedAnnotationBeanPostProfessor 也会负责处理@Value 注解.例. 如下:

@Component(Value = "sample")

public class Sample

@Value("Some currency")

private String currency

........



currency 字段使用@Value 注解. @Value 注解的value 特性指定字段的默认值. 指定value 特性是可选的. 因此,@Value(value = "Some currency") 与("Some currency") 相同.

在@Value 注解中使用Spring 表达式语言(SpEL)

例:

@Componet(value ="sample")

public class Sample

@value("#configuration.enviroment")

private String enviroment;

@value("#configuration.getContry()")

private String country;

@Value("configuration.state")

private String state;

.......



@Component("configuration")

public class Configuration

public static String environment ="DEV";

public String getContry()

return "Some country";



public STring getState()

return "Some state";



public String[] splitName(String name)

return name.split(" ");



public String getCity()

return "Some city";





通过以上例子可以知道, 可以使用SpEL 从其他bean 中 获取配置信息.

在方法级 和方法参数级使用 @Value 主机

@Component(value = "sample")

public class Sample

..............

private String[] splitName;

private String city;

@Autowrited

public void splitName(@Value("#configuration.splitName('FirstName LastName')")  String[] spitName)



this.splitName  = splitName;



@Autowrited

@Value("#configuration.getCity()")

public void city(String city)

this.city = city;



..............................



在SpEL 中还可以使用数学, 关系和 逻辑运算符.

@Value("#3>2 && 4>3")

在SpEL 中可以获取bean的引用.

@Value("#configuration")

在SpEL 中使用正则表达式.

@Value("#('abcd@xyz.com' matches '^[A-Za-z0-9+_.-]+(.+)$') == true ?true :false")

在SpEL 中使用映射和列表

在基于XML 的bean 定义中指定SpEL 表达式.

Spring 注解驱动WEB 注解开发

Spring 注解驱动(二)Servlet 3.0 注解驱动在 Spring MVC 中的应用

Spring 系列目录(https://www.cnblogs.com/binarylei/p/10198698.html)

在 Servlet 3.0 时支持注解启动,不再需要 web.xml 配制文件。详见《Servlet 3.0 规范(二)注解规范》:https://www.cnblogs.com/binarylei/p/10204208.html

一、Servlet 3.0 与 Spring MVC 整合

@HandlesTypes(WebApplicationInitializer.class)
public class SpringServletContainerInitializer implements ServletContainerInitializer {
    @Override
    public void onStartup(@Nullable Set<Class<?>> webAppInitializerClasses, ServletContext servletContext)
            throws ServletException {

        List<WebApplicationInitializer> initializers = new LinkedList<>();
        if (webAppInitializerClasses != null) {
            for (Class<?> waiClass : webAppInitializerClasses) {
                // WebApplicationInitializer 的实现类
                if (!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) &&
                        WebApplicationInitializer.class.isAssignableFrom(waiClass)) {
                    try {
                        initializers.add((WebApplicationInitializer)
                                ReflectionUtils.accessibleConstructor(waiClass).newInstance());
                    } catch (Throwable ex) {
                        throw new ServletException("Failed to instantiate WebApplicationInitializer class", ex);
                    }
                }
            }
        }

        if (initializers.isEmpty()) {
            servletContext.log("No Spring WebApplicationInitializer types detected on classpath");
            return;
        }

        // 执行 onStartup
        AnnotationAwareOrderComparator.sort(initializers);
        for (WebApplicationInitializer initializer : initializers) {
            initializer.onStartup(servletContext);
        }
    }

}

Spring MVC 启动时会调用 WebApplicationInitializer 实现类的 onStartup 方法启动 WEB 容器。WebApplicationInitializer 的继承关系如下:

WebApplicationInitializer
    |- AbstractContextLoaderInitializer
        |- AbstractDispatcherServletInitializer
            |- AbstractAnnotationConfigDispatcherServletInitializer
  • AbstractContextLoaderInitializer 创建 Root 根容器并注册 ContextLoaderListener,创建根容器由子类实现。核心方法:registerContextLoaderListener

  • AbstractDispatcherServletInitializer 创建 Servlet 容器,并注册 DispatcherServlet 和 Filete,创建根容器由子类实现。核心方法:registerDispatcherServlet

  • AbstractAnnotationConfigDispatcherServletInitializer 创建 Root 和 Servlet 容器。核心方法:createRootApplicationContext、createServletApplicationContext

断点调试,webAppInitializerClasses 有以下类,显然只有一个实现类 MyAbstractAnnotationConfigDispatcherServletInitializer 执行了 onStartup 方法。

0 = {Class@4467} "class org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer"
1 = {Class@4468} "class org.springframework.web.servlet.support.AbstractDispatcherServletInitializer"
2 = {Class@4469} "class org.springframework.web.server.adapter.AbstractReactiveWebInitializer"
3 = {Class@4470} "class org.springframework.web.context.AbstractContextLoaderInitializer"
4 = {Class@4471} "class com.github.binarylei.MyAbstractAnnotationConfigDispatcherServletInitializer"

二、WebMvcConfigurer 接管 xml 配置

(1) @EnableWebMvc

开启 Spring 高级功能,相当于 <mvc:annotation-driven/>

(2) WebMvcConfigurer

对应以前 XML 配置中的每一项,以 interceptors 为例,其余详见官方文档:Spring 注解配置类 WebMvcConfigurer(https://docs.spring.io/spring/docs/5.1.3.RELEASE/spring-framework-reference/web.html#mvc-config)

@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LocaleChangeInterceptor());
        registry.addInterceptor(new ThemeChangeInterceptor()).addPathPatterns("/**").excludePathPatterns("/admin/**");
        registry.addInterceptor(new SecurityInterceptor()).addPathPatterns("/secure/*");
    }
}

以上代码相当于之前 XML 中的

<mvc:interceptors>
    <bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor"/>
    <mvc:interceptor>
        <mvc:mapping path="/**"/>
        <mvc:exclude-mapping path="/admin/**"/>
        <bean class="org.springframework.web.servlet.theme.ThemeChangeInterceptor"/>
    </mvc:interceptor>
    <mvc:interceptor>
        <mvc:mapping path="/secure/*"/>
        <bean class="org.example.SecurityInterceptor"/>
    </mvc:interceptor>
</mvc:interceptors>

三、模拟 Spring Boot 将 WEB 打成 jar 包运行

Spring 官方文档注解配置

使用 tomcat7-maven-plugin 插件模拟 Spring Boot。

目录结构

(1) WebApplicationInitializer 实现类

public class MyAbstractAnnotationConfigDispatcherServletInitializer extends
        AbstractAnnotationConfigDispatcherServletInitializer {

    // Root 容器配置
    protected Class<?>[] getRootConfigClasses() {
        return new Class[0];
    }

    // Servlet 容器配置
    protected Class<?>[] getServletConfigClasses() {
        return new Class[]{MyServletConfig.class};
    }

    // Servlet Mapping,取代 web.xml 中的 servlet-mapping 配置
    protected String[] getServletMappings() {
        return new String[]{"/"};
    }

    // Filter 配置,取代 web.xml 中的 filter 配置
    @Override
    protected Filter[] getServletFilters() {
        CharacterEncodingFilter encodingFilter = new CharacterEncodingFilter();
        encodingFilter.setEncoding("utf-8");
        encodingFilter.setForceRequestEncoding(true);
        encodingFilter.setForceResponseEncoding(true);

        return new Filter[]{encodingFilter};
    }
}

// 取代 spring-mvc.xml 配制
@Configuration
@ComponentScan(basePackages = "com.github.binarylei",
        excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Controller.class)})
public class MyRootConfig {
}

// 取代 spring-context.xml 配制
@Configuration
@ComponentScan(basePackages = "com.github.binarylei",
        includeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Controller.class)})
public class MyServletConfig {

    @Bean
    public ViewResolver viewResolver(){
        InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
        viewResolver.setViewClass(JstlView.class);
        viewResolver.setPrefix("/WEB-INF/view/");
        viewResolver.setSuffix(".jsp");
        return viewResolver;
    }
}

(2) tomcat7-maven-plugin 配制

tomcat7-maven-plugin 官网:http://tomcat.apache.org/maven-plugin-2.1/executable-war-jar.html

<packaging>war</packaging>
<properties>
    <spring.version>5.1.0.RELEASE</spring.version>

    <project.build.sourceEncoding>utf-8</project.build.sourceEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
</properties>

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>3.1.0</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>jstl</groupId>
        <artifactId>jstl</artifactId>
        <version>1.2</version>
    </dependency>
</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-war-plugin</artifactId>
            <version>3.2.0</version>
            <configuration>
                <failOnMissingWebXml>false</failOnMissingWebXml>
            </configuration>
        </plugin>
        <plugin>
            <groupId>org.apache.tomcat.maven</groupId>
            <artifactId>tomcat7-maven-plugin</artifactId>
            <version>2.1</version>
            <executions>
                <execution>
                    <id>tomcat-run</id>
                    <goals>
                        <goal>exec-war-only</goal>
                    </goals>
                    <phase>package</phase>
                    <configuration>
                        <path>/</path>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

(3) 运行

执行 mvn package 后生成了两个文件:spring-war-1.0.0.war 和 spring-war-1.0.0-war-exec.jar

# localhost:8080/
java -jar spring-war-1.0.0-war-exec.jar 
# IDEA remote 调试时(suspend=y)
java -jar -agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=*:5005 spring-war-1.0.0-war-exec.jar

tomcat 启动远程时报错:https://www.aliyun.com/jiaocheng/1443062.html


每天用心记录一点点。内容也许不重要,但习惯很重要!

以上是关于Spring 注解驱动开发的主要内容,如果未能解决你的问题,请参考以下文章

Spring 注解驱动WEB 注解开发

Spring注解驱动开发--项目搭建

Spring注解@驱动开发

Spring注解驱动开发在@Import注解中使用ImportBeanDefinitionRegistrar向容器中注册bean

Spring注解驱动开发

spring注解驱动开发