文章目录
1. 注解(Annotation)
Annotation 是可以在编译、运行阶段读取的
借助 Annotation 来实现一些功能增强,和 Python 的装饰器有类似之处
//这个代码很平常,但是多了一个 @Service
//这个注解的作用是声明引用该注解的Java类为Service对象
@Service
public class MessageServiceImpl implements MessageService{
public String getMessage() {
return "Hello World!";
}
}
Annotation 也是一个 Java 类,只是有点特别。看看 Service 这个Annotation 的源代码
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.1 Target
java.lang.annotation.Target
,自身也是一个注解,只有一个数组属性,用于设定该注解的目标范围,,比如说可以作用于类或方法等,因为是数组,所以可以同时设定多个范围,具体的作用类型配置在 java.lang.annotation.ElementType
枚举类中,常用的有:
ElementType.TYPE
可以用于类、接口、枚举类上ElementType.FIELD
可以作用于类的属性上ElementType.METHOD
可以作用于类的方法上ElementType.PARAMETER
作用于类的参数上
如果想要同时作用于类和方法上:
@Target({ElementType.TYPE, ElementType.METHOD})
1.2 Retention
java.lang.annotation.Retention
,自身也是一个注解,用于声明该注解的生命周期,它的值定义在java.lang.annotation.RetentionPolicy
枚举类中,有三个值可以选择:
- SOURCE:纯注释作用
- CLASS:在编译阶段有效
- RUNTIME:在运行时有效
@Retention(RetentionPolicy.RUNTIME)
1.3 @interface
声明当前的 Java 类型是 Annotation,固定语法
1.4 Annotation 属性
String value() default "";
约定了属性的类型和属性名称,default 代表的是默认值
2. Spring Bean
IoC(控制反转)容器是 Spring 框架最核心的组件,没有 IoC 容器就没有 Spring 框架。在 Spring 框架中,主要通过**依赖注入(DI)**来实现 IoC 。所有的 Java 对象都会通过 IoC 容器转变为 Bean(Spring 对象的一种称呼)。基本上所有的 Bean 都是由 接口+实现类 完成的,用户想要获取 Bean 的实例直接从 IoC 容器获取就可以了,不需要关心实现类。
org.springframework.context.ApplicationContext
接口类定义容器的对外服务,通过这个接口,我们可以轻松的从 IoC 容器中得到 Bean 对象。在启动 Java 程序的时候必须先要启动 IoC 容器,Annotation 类型的 IoC 容器对应的类是org.springframework.context.annotation.AnnotationConfigApplicationContext
,如果要启动 IoC 容器,可以运行下面的代码:
//启动 IoC 容器
ApplicationContext context = new AnnotationConfigApplicationContext("fm.douban"); //填写的是包名
这段代码的意义就是启动 IoC 容器,自动加载包 fm.douban 下的 Bean(只要是应用了 Spring 注解的类都可以被加载,前提是在这个包下面)。
Spring 官方声明为 Spring Bean 的注解有以下几种:
org.springframework.stereotype.Service
org.springframework.stereotype.Component
org.springframework.stereotype.Controller
作用于 Web Beanorg.springframework.stereotype.Repository
作用于持久化相关 Bean
只要我在类上引用这类注解,那么都可以被 IoC 容器加载。
依赖注入的第一步是完成容器的启动,第二部就是真正的完成依赖注入行为了。
依赖注入让我们得到其他 Bean 的实例相当简单,只需要在属性上添加注解。
例如:
import org.springframework.beans.factory.annotation.Autowired;
@Autowired
private SongService songService;
当然,还有一个前提:当前类是 Spring Bean,在本类上添加 @Service
3. Spring Resource
处理文件的方案 Spring Resource,在 Java 工程中文件的几种情况:
- 文件在电脑的某个位置,比如
d:/mywork/a.doc
- 文件在工程目录下,比如
mywork/tuo.png
- 文件在工程的
src/main/resource
目录下
在第三种情况下,jar 文件是从包路径开始的,Maven 工程编译后,会自动去掉 src/main/java
、src/main/resource
目录。
问题:如何读取 jar 内部的文件?
方案:classpath 指定的文件不能解析成 File 对象,但是可以解析成 InputStream,我们借助 Java IO 就可以读出来了。classpath 类似虚拟目录,它的根目录是从 /
开始代表的是src/main/java
或者src/main/resource
目录
先要添加依赖:
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>```
import java.io.IOException;
import java.io.InputStream;
public class Test {
public static void main(String[] args) {
// 读取 classpath 的内容
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();
}
}
}
InputStream in = Test.class.getClassLoader().getResourceAsStream("data.json");
这段代码的含义就是从 Java 运行的类加载器(ClassLoader实例中查找文件,Test.class
指的是当前的 Test.java 编译后的 Java class 文件
在 Spring 当中定义了一个 org.springframework.core.io.Resource
类来封装文件,这个类的优势在于可以支持普通的 File 也可以支持 classpath 文件,并且在 Spring 中通过 org.springframework.core.io.ResourceLoader
服务来提供任意文件的读写,可以在任意的 Spring Bean 中引入ResourceLoader
创建一个自己的 FIleService:
public interface FileService {
String getContent(String name);
}
实现类:
import fm.douban.service.FileService;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.io.InputStream;
@Service
public class FileServiceImpl implements FileService {
@Autowired
private ResourceLoader loader;
@Override
public String getContent(String name) {
try {
InputStream in = loader.getResource(name).getInputStream();
return IOUtils.toString(in,"utf-8");
} catch (IOException e) {
return null;
}
}
}
此服务的调用:
ApplicationContext context = new AnnotationConfigApplicationContext("fm.douban");
FileService fileService = context.getBean(FileService.class);
String content = fileService.getContent("classpath:data/urls.txt");
System.out.println(content);
在 Spring Resource 当中,把本地文件、classpath文件、远程文件都封装成 Resource 对象来统一加载,这就是它强悍的地方
4. Spring Bean 的生命周期
里面有一个 init 方法,名称是任意的,我们是通过注解来声明 init 的
import javax.annotation.PostConstruct;
@Service
public class SubjectServiceImpl implements SubjectService {
@PostConstruct
public void init(){
System.out.println("启动啦");
}
}
只要在方法上添加 @PostConstruct
注解,代表该方法在 Spring Bean 启动后会自动执行