文章目录
1、java注解(Anotation)
java 推出一种注释机制Annotation
,它可以在编译、运行阶段读取。
这个特点带来了很多扩展空间,并且不会污染源代码。在Spring中就重度使用Annotation
。
Annotation
也是一个java类:
图中为一个注解类Annotation
的定义,由此可见Annotation
由多个Annotation
组合而成。
1.1、@Target
java.lang.annotation.Target
自身就是一个注解,它只有一个属性(并且这个属性是数组),用于设定该注解(Target修饰的注解)的作用目标范围,比如说是作用于类,还是方法,还是属性等。因为是数组,所以可以设定多个目标。
具体的可作用类型配置在java.lang.annotation.ElementType
枚举类中,如下列举几个常用的:
- ElementType.TYPE
作用于类
- ElementType.FIELD
作用于类的属性
- ElementType.MATHOD
作用于类的方法
- ElementType.PARAMETER
作用于类的参数
比如想要Target修饰的注解作用于类和方法:
@Target({ElementType.TYPE,ElementType.METHOD})
这四种类型的注解例子:
1.1.1、ElementType.TYPE
@Service
public class MessageServiceImpl implements MessageService{
public String getMessage() {
return "Hello World!";
}
}
1.1.2、ElementType.FIELD
public class MessageServiceImpl implements MessageService{
@Autowired
private WorkspaceService workspaceService;
}
1.1.3、ElementType.MATHOD
public class MessageServiceImpl implements MessageService{
@ResponseBody
public String getMessage() {
return "Hello World!";
}
}
1.1.4、ElementType.PARAMETER
public class MessageServiceImpl implements MessageService{
public String getMessage(@RequestParam("msg")String msg) {
return "Hello "+msg;
}
}
1.2、@Retention
java.lang.annotation.Retention
,该注解用于声明注解生命周期,就是在编译、运行的哪个环节有效,它的值定义在java.lang.annotation.RetentionPolicy
枚举类中,有三个枚举值:
- SOURCE:纯注释作用
- CLASS:编译阶段有效
- RUNTIME:运行阶段有效
@Retention(RetentionPolicy.RUNTIME);
表示运行阶段有效
1.3、@Documented
java.lang.annotation.Documented
,这个注解的作用是将所修饰的注解中的元素包含到JavaDoc文档中,一般情况下都会加这个注解。
1.4、@interface
声明当前java类型为Annotation
1.5、Annotation 的属性
未完待续
2、Spring Bean
IoC(Inversion of Control,控制反转)容器是Spring框架最核心组件。它是面向对象编程中的一种设计原则,可降低计算机代码之间的耦合度。
Spring框架中主要通过依赖注入(Dependnecy Injection,DI)来实现IoC。Spring中所有的java对象都会通过IoC容器转变为Bean(Spring对象的一种称呼),构成应用程序主干 和 由Spring IoC容器管理 的对象称为beans,beans和它们之间的依赖关系反映在容器使用的配置元数据中。基本上所有的Bean都是由接口+实现类完成的,用户想获取Bean的实例直接从IoC里获取就好了,不必关心实现类。
Spring主要有两种配置元数据的方式,一种是基于XML、一种是基于Annotation方案的,目前主流的方案是基于Annotation的。
org.springframework.context.ApplicationContext
接口类定义容器的对外服务,通过这个接口,可以轻松地从IoC容器中获取Bean对象。使用前得先启动IoC容器。
Annotation类型的IoC容器对应的类是:org.springframework.context.annotation.AnnotationConfigApplicationContext
启动IoC容器的代码:
ApplicationContext context = new AnnotationConfigApplicationContext("fm.douban");
这样就会启动IoC容器,并且自动加载包fm.douban
下的Bean,该包内引用了Spring注解的类都会被加载。
AnnotationConfigApplicationContext
类的构造函数有两种:
- AnnotationConfigApplicationContext(String basePackage),根据包名实例化
- AnnotationConfigApplicationContext(Class clazz),根据自定义包扫描行为进行实例化
Spring官方声明为Spring Bean的注解有以下几种:
org.springframework.stereotype.Component
@Component注解是通用的Bean注解,其余三个注解都是扩展自Component。org.springframework.stereotype.Service
@Service正如这个名称一样,代表的是Service Bean。org.springframework.stereotype.Controller
@Controller作用于Web Bean。org.springframework.stereotype.Repository
@Repository作用于持久化相关Bean。
以上四个注解都可以被IoC容器加载,一般情况下使用@Service,,Web服务就用@Controller。
IoC容器就像一个大工厂一样,我们不关心工厂如何生产,只需要使用工厂生产的产品。
依赖注入第一步启动容器,然后才是依赖注入行为。
依赖注入是一种编程思想,是一种获取其他实例的规范。
依赖注入让我们得到Bean实例相当简单,只需要在属性上添加注解(前提是当前需要获取Bean实例的类是Spring Bean,即当前类能被IoC容器加载)。
@Autowired
private SongService songService;
Autowired的路径是
org.springframework.beans.factory.annotation.Autowired
3、Spring Resource
在java内部,一般把文件路径称为classpath,所以读取内部文件就是从classpath内读取,classpath指定的文件不能解析成File对象(但是可以解析成InputStream对象)。
classpath类似虚拟目录,它的根目录是从/
开始代表的是src/main/java
或者src/main/resources
目录
3.1、用类加载器加载classpath里的文件
Java拥有很多丰富的第三方类库给我们使用,读取文件,我们可以使用commons-io这个库来,需要在pom.xml下添加依赖
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
测试代码:
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文件
3.2、用Spring Resource加载文件
Spring擅长的就是封装各种服务 。
在Spring中定义了一个org.springframework.core.io.Resource
类来封装文件,这个类的优势在与可以封装File和classpath文件
并且在Spring中通过org.springframework.core.io.ResourceLoader
服务来提供文件的读写,可以在任意的Spring Bean中引入ResourceLoader
用Resource来构建服务:
public interface FileService {
String getContent(String name);
}
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;
}
}
}
服务的调用:
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Application {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext("fm.douban");
FileService fileService = context.getBean(FileService.class);
String content = fileService.getContent("classpath:data/urls.txt");
System.out.println(content);
String content2 = fileService.getContent("https://www.zhihu.com/question/34786516/answer/822686390");
System.out.println(content2);
}
}
代码中content2
获取到的是网页的内容。
所以,Spring Resource中,把本地文件、classpath文件、远程文件都封装成Resource对象来统一加载。
4、Spring Bean的生命周期
其中 init() 方法(init这个名称是可以任意的,因为我们是通过注解来声明init)
import javax.annotation.PostConstruct;
@Service
public class SubjectServiceImpl implements SubjectService {
@PostConstruct
public void init(){
System.out.println("启动啦");
}
}
只要添加了@PostConstruct
注解,就代表方法在Spring Bean启动后会自动执行。(所以可以用它来代替static代码块)。