Annotation(注解)
注解本质上是Java推出的一种特殊的可在编译、运行阶段读取的注释。
package org.springframework.stereotype;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.core.annotation.AliasFor;
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Service {
@AliasFor(
annotation = Component.class
)
String value() default "";
}
1. Target
本身也是一个注解,只有一个数组属性,用于设定该注解的目标范围,可同时设定多个范围。
// 用于类、接口类、枚举类
ElementType.TYPE
// 用于类的属性
ElementType.FLELD
// 用与类的方法上
ElementType.METHOD
// 用于类的参数上
ElementType.PARAMETER
// 例子
@Target({ElementType.TYPE,ElementType.METHOD})
2. Retention
即声明该注解的生命周期,三个值可选SOURCE
(纯注释)、CLASS
(编译阶段)、RUNTIME
(运行时)
@Retention(RetentionPolicy.RUNTIME)
3. Documented
其作用就是将注释的元素包含到JavaDoc文档中,一般情况下,都会添加这个注解
4. @interface
即声明当前的Java类型为Annotation,固定语法
5. Annotation属性
类似类的属性,约定该属性的类型和属性名称,默认属性名称是value可省略
String value() default "";
6. 举个栗子
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequestParam {
// 即别名的意思,通过别名也可以访问该属性
@AliasFor("name")
String value() default "";
@AliasFor("value")
String name() default "";
boolean required() default true;
String defaultValue() default ValueConstants.DEFAULT_NONE;
}
Spring Bean
IoC(Inversion of Control,控制反转)容器是Spring框架最核心的组件,
主要通过依赖注入(Dependecy Injection,DI)实现IoC
,所有的Java对象都会通过该容器转变为Bean
(Spring对象的一种称呼)。
// 运行下面的代码启动IoC容器
ApplicationContext context =
new AnnotationConfigApplicationContext("com.kevin.spring");
// 不再需要实例化接口的实现类,而是直接使用接口(面向接口编程)
FileService fileService = context.getBean(FileService.class);
这段代码的含义就是启动IoC容器,并且会加载包com.kevin.spring
下的Bean(只要引用了Spring注解的类都可以被加载)
// Spring官方声明为Spring Bean的注解有:
1. 通用的Bean注解,其余三个是器扩展
org.springframework.stereotype.Component
org.springframework.stereotype.Service
2. 作用于Web Bean,一般情况下使用@Service,如果是Web则用@Controller
org.springframework.stereotype.Controller
org.springframework.stereotype.Repository
加注解的作用,是让 Spring 系统 自动 管理 各种实例。
所谓 管理,就是用 @Service 注解把 SubjectServiceImpl和 SongServiceImpl等等所有服务实现,都标记成 Spring Bean;然后,在任何需要使用服务的地方,用@Autowired 注解标记,告诉 Spring 这里需要注入实现类的实例。
项目启动过程中,Spring 会 自动 实例化服务实现类,然后自动注入到变量中,不需要开发者大量的写new代码了,就解决了上述的开发者需要大量写代码而导致容易出错的问题,
@Service 和 @Autowired 是相辅相成的:如果 SongServicelmp没有加 @Service ,就意味着没有标记成 Spring Bean,那么即使加了 @Autowired 也无法注入实例;而
private SongService songService; 属性忘记加 @Autowired Spring Bean 亦无法注入实例。二者缺一不可。
每个 Annotation(注解)都有各自特定的功能,Spring 检查到代码中有注解,就自动完成特定功能,减少代码量、降低系统复杂度。
初学 Spring,需要理解 并牢记 常见的这些注解的功能和作用。
Spring Resource
Maven执行package的时候,会把resource目录下的文件一起打包进jar包里,jar文件是从包路径开始的,Maven工程编译后会自动去掉src/main/java
、src/main/resources
目录(一般我们的数据文件都会放在resources目录下)
classpath
在Java内部我们一般将文件路径称为classpath
,其指定的文件不能解构成File对象化,但是可以解析成InputStream,借助JavaIO就可以取出来了
public class Test {
public static void main(String[] args) {
// 读取 classpath 的内容
// 从Java运行的类加载器(ClassLoader)实例中查找文件
// Test.class指的是当前Test.java文件编译后的Java Class文件
InputStream in =
Test.class.getClassLoader().getResourceAsStream("data.json");
// 使用 commons-io 库读取文本
try {
String content = IOUtils.toString(in, "utf-8");
System.out.println(content);
} catch (IOException e) {
// IOUtils.toString 有可能会抛出异常,需要我们捕获一下
e.printStackTrace();
}
}
}
ResourceLoader
在Spring中定义了一个org.springframework.core.io.Resource
类来封装文件,这个类的优势在于既可以封装普通的File也可以支持classpath文件,甚至是远程文件。并且在Spring中通过org.springframework.core.io.ResourceLoader
可以在任意的Spring Bean中引入ResourceLoader
,举个读取resource文件夹下的json文件
package com.kevin.spring.service.impl;
import ...
@Service
public class SongListServiceImpl implements SongListService {
private static Map<String,SongList> songListMap = new HashMap<>();
@Autowired
private ResourceLoader loader;
@PostConstruct
public void init() {
try {
InputStream in =
loader.getResource("classpath:data/songlists.json").getInputStream();
String jsonString = IOUtils.toString(in, "utf-8");
SongList[] lists = JSON.parseObject(jsonString, SongList[].class);
for(SongList songList : lists){
songListMap.put(songList.getId(),songList);
}
} catch (IOException e) {
e.fillInStackTrace();
}
}
@Override
public SongList get(String songListId) {
return songListMap.get(songListId);
}
}
Spring Bean 的生命周期
大部分时候我们只需要掌握init
方法,其方法名是任意的,因为我们是通过注解来声明该方法的
import javax.annotation.PostConstruct;
@Service
public class SubjectServiceImpl implements SubjectService {
// 这个注解意思是该方法在Spring Bean启动后自动执行
// 因此可以将一些初始化的代码放入其中,例如static代码块
@PostConstruct
public void init(){
System.out.println("启动啦");
Subject subject = new Subject();
subject.setId("s001");
subject.setName("成都");
subject.setMusician("赵雷");
subjectMap.put(subject.getId(), subject);
}
}