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 包运行
使用 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注解驱动开发在@Import注解中使用ImportBeanDefinitionRegistrar向容器中注册bean