Spring及其相关属性简介

Spring

Spring 是 Java 语言中必须要掌握的框架,它已经有超过10年的稳定期了,基本上所有采用 Java 语言的公司都会采用 Spring Framework,这个框架基本上是全能的,它涵盖了 Java 的各个领域。从事 Java 工作没有不会 Spring 的,在我们学习完 Java 语言后,我们就要开始学习 Spring Framework 啦,目前 Spring 最新的框架是 5.x,Spring 框架每年的更新也挺多的,所以我们尽可能掌握最新的版本。

依赖注入(DI)是 Spring 最核心的技术点(我们在后面还会继续运用到),Spring 所有的技术方案都是基于 DI 来发展的。对于初学者来说理解 DI 会有一些困难,所以我们先要做到的是熟练使用 Spring 的技能。

Maven简介

Maven是一个项目管理和构建自动化工具。但是对于我们程序员来说,我们最关心的是它的项目构建功能。所以这里我们介绍的就是怎样用 Maven 来满足我们项目的日常需要。如果说 Spring 是必须要学习的框架,那么 Maven 就是 Java 必须要掌握的工具。

Maven 提供了一个命令行工具可以把工程打包成 Java 支持的格式(比如 jar),并且支持部署到中央仓库里,这样使用者只需要通过工具就可以很快捷的运用其他人写的代码,只需要你添加依赖即可。

Maven的系统架构如下:
在这里插入图片描述
从这个架构里可以看到借助于中央仓库,我们可以把 Java 代码任意的共享给别人,这对于团队协同开发来说是至关重要的,可以说 Java 工程化发展到现在,Maven 起到了决定性的作用。

Maven规定了工程目录的结构:
在这里插入图片描述
这里的${basedir} 代表的是 Java 工程的根路径,在我们这里就是工程的根目录。一个 Maven 项目在默认情况下会产生 JAR (Java 的一种压缩格式)文件,另外 ,编译后的 classes 会放在 ${basedir}/target/classes 下面, JAR 文件会放在 ${basedir}/target 下面。

Spring Bean容器

IoC(Inversion of Control,控制反转)容器是Spring框架中最核心的组件,是构成框架最重要的内容。
IoC(Inversion of Control,控制反转)是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度。
在Spring框架中,主要通过依赖注入(Dependency Injection,简称DI)来实现IoC。
在Spring中,Java对象通过IoC转化为Bean对象。所有的Bean对象基本都是由接口+实现类实现的,用户想要获取 Bean 的实例直接从 IoC 容器获取就可以了,不需要关心实现类。
目前主流的方案是通过Annotation来配置元数据。org.springframework.context.ApplicationContext 接口类定义容器的对外服务,通过这个接口,我们可以轻松的从 IoC 容器中得到 Bean 对象。我们在启动 Java 程序的时候必须要先启动 IoC 容器。
Annotation类型的IoC容器对应的类为:

org.springframework.context.annotation.AnnotationConfigApplicationContext

如果我们要启动IoC容器,可以运行如下代码:

ApplicationContext context = 
    new AnnotationConfigApplicationContext("package_name");

启动后,在这个包名下,只要引用了Spring注解的类都可以被加载。
Spring官方声明为SpringBean的注解有如下几种:

  • org.springframework.stereotype.Service
  • org.springframework.stereotype.Component
  • org.springframework.stereotype.Controller
  • org.springframework.stereotype.Repository
    只要在类上引用这些注解,就可以被IoC容器加载。
    @Component:通用的Bean注解,其余三个注解都是拓展自Component。
    @Service:作用于Service Bean。
    @Controller:作用于Web Bean。
    @Repository:作用于持久化相关Bean。
    一般情况下,我们使用@Service;如果是Web层服务就使用@Controller

完成容器的启动,下一步就要完成依赖注入。
假设现在我们要在UserService中使用PlayService服务类下的play方法,我们需要在类中建立一个setPlayService方法用于传入service对象,此时我们就需要在外部调用这个方法,才能传入PlayService对象。一旦需要依赖的服务特别多,这个代码体量就会变得很大。

UserService userService = new UserServiceImpl();
PlayService playService= new PlayServiceImpl();
userService .setPlayService(playService);

这个时候我们就可以使用依赖注入的方法来完成服务依赖的加载。

  1. 首先,在service层增加@Service注解;
@Service
public class PlayServiceImpl implementsPlayService {
......
}
  1. 在依赖此服务的业务中使用@Autowired注解注入Service Bean;
@Autowired
private PlayService playService;
  1. 注入完成,不再需要使用set方法来导入Service Bean了。

添加注解的作用,是为了让Spring项目自动管理各种实例。
所谓管理,就是用 @Service 注解把 SubjectServiceImplSongServiceImpl 等等所有服务实现,都标记成 Spring Bean ;然后,在任何需要使用服务的地方,用 @Autowired 注解标记,告诉 Spring 这里需要注入实现类的实例。

Spring Resource

Spring Resource用于处理程序读取文件的业务。

学习之前,首先需要了解文件在Java工程中的几种情况:

  1. 文件在电脑上的某个位置,如D:/java/jdk1.8;
  2. 文件在工程目录下,如mywork/a.png;
  3. 文件在工程的src/main/resources目录下,这里是用于存放Maven文件的地方。
    前两种情况我们使用File对象就可以进行读写,但第三种比较特殊,因为Maven在打包工程的时候会将resources目录下的文件一起打包进jar包,这种情况我们使用File对象是读取不到的。
    例如我们读取下图的两个文件:
    在这里插入图片描述
    代码如下:
import java.io.File;

/**
 * Test
 */
public class Test {

  public static void main(String[] args) {

    File file = new File("mywork/readme.md");
    if(file.exists()){
      System.out.println("readme.md 文件存在");
    }

    File file2 = new File("src/main/resources/nani.jpeg");
    if(file2.exists()){
      System.out.println("nani.jpeg 文件存在");
    }

  }

}

此时我们是可以读取到两个文件的。但是在大多数情况下我们并没有清晰的文件目录,而是导入jar包:
在这里插入图片描述
这是我们无法找到src/main/resources/nani.jpeg文件。
使用解压工具将jar包解压,我们会发现目录出现了变化:
在这里插入图片描述
这就是 Java 文件系统和计算机文件系统的差异,工程目录最后是要编译成 jar 文件的,jar文件是从包路径开始的。Maven 工程编译后,会自动去掉 src/main/javasrc/main/resources 目录。
此时,我们需要借助classpath读取文件。

classpath

在 Java 内部当中,我们一般把文件路径称为 classpath,所以读取内部的文件就是从 classpath 内读取,classpath 指定的文件不能解析成 File 对象,但是可以解析成 InputStream,我们借助 Java IO 就可以读取出来了。
想要实现classpath内读取文件,我们可以使用 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");

这段代码的含义是指在当前的Test.java文件编译后的Test.class文件中Java运行的类加载器(ClassLoader)实例中查找文件。

那么,我们用Spring Resources能做什么呢?
我们可以使用org.springframework.core.io.Resource类来封装文件,这个类的优势在于可以支持普通的File文件也可以支持classpath文件,并且在Spring中通过org.springframework.core.io.ResourceLoader服务来提供任意文件的读写,通过在任意的Spring Bean中引入ResourceLoader:

@Autowired
private ResourceLoader loader;

现在让我们来看一下在 Spring 当中如何读取文件,我们创建一个自己的 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;
        }
    }
}

之后通过依赖注入调用服务:

 FileService fileService = context.getBean(FileService.class);
  String content = fileService.getContent("classpath:data/urls.txt");
  System.out.println(content);

他的功能不仅于此,它还可以读取本地或工程内的文件:

String content2 = fileService.getContent("file:mywork/readme.md");
System.out.println(content2);

甚至还能读取远程文件:

String content2 = fileService.getContent("https://www.zhihu.com/question/34786516/answer/822686390");
System.out.println(content2);

总而言之,在 Spring Resource 当中,可以把本地文件、classpath文件、远程文件都封装成 Resource 对象来统一加载,这就是它的强悍的地方。

Spring Bean 的生命周期(LifeCycle)

为了更好的管理 Bean,Spring Bean 提供了生命周期管理能力,这将极大的提高了工程化的能力。
生命周期就是描述一个程序从开始到结束的流程、状态。很多编程框架都提供生命周期的管理,提供类似实例的从开始到结束的状态管理。

在这里插入图片描述
大部分时候我们只需要掌握init方法就行。这个init方法的名字可以是任意的,init是通过注解来声明的。我们以SubjectService为例:

import javax.annotation.PostConstruct;

@Service
public class SubjectServiceImpl implements SubjectService {

  @PostConstruct
  public void init(){
      System.out.println("启动啦");
  }

}  

我们只要在方法上添加@PostConstruct注解,就代表该方法在 Spring Bean 启动后会自动执行。
执行后可以看到init内的内容被先执行出来了。
在实际用用中,我们可以在init中首先加载一些预设的属性,使数据先初始化,之后被服务调用。Spring 声明周期可以让我们更轻松的初始化一些行为以及维护数据。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值