前言

Spring 提供了非常多的扩展接口,官方将这些接口称之为钩子,这些钩子会在特定的时间被回调,以此来增强 Spring 功能,众多优秀的框架也是通过扩展这些接口,来实现自身特定的功能,如 SpringBoot、mybatis 等。

1、Aware 系列接口

Aware 从字面意思理解就是“知道”、“感知”的意思,是用来获取 Spring 内部对象的接口。Aware 自身是一个顶级接口,它有一系列子接口,在一个 Bean 中实现这些子接口并重写里面的 set 方法后,Spring 容器启动时,就会回调该 set 方法,而相应的对象会通过方法参数传递进去。我们以其中的 ApplicationContextAware 接口为例。

ApplicationContextAware

大部分 Aware 系列接口都有一个规律,它们以对象名称为前缀,获取的就是该对象,所以 ApplicationContextAware 获取的对象是 ApplicationContext 。

public interface ApplicationContextAware extends Aware {

	void setApplicationContext(ApplicationContext applicationContext) throws BeansException;
}

ApplicationContextAware 源码非常简单,其继承了 Aware 接口,并定义一个 set 方法,参数就是 ApplicationContext 对象,当然,其它系列的 Aware 接口也是类似的定义。其具体使用方式如下:

public class Test implements ApplicationContextAware {

    private ApplicationContext applicationContext;

    @Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}

在 Spring 启动过程中,会回调 setApplicationContext 方法,并传入 ApplicationContext 对象,之后就可对该对象进行操作。其它系列的 Aware 接口也是如此使用。具体的调用时机会在后面详细介绍。

以下是几种常用的 Aware 接口:

  • BeanFactoryAware:获取 BeanFactory 对象,它是基础的容器接口。
  • BeanNameAware:获取 Bean 的名称。
  • EnvironmentAware:获取 Environment 对象,它表示整个的运行时环境,可以设置和获取配置属性。
  • ApplicationEventPublisherAware:获取 ApplicationEventPublisher 对象,它是用来发布事件的。
  • ResourceLoaderAware:获取 ResourceLoader 对象,它是获取资源的工具。

2、InitializingBean

InitializingBean 是一个可以在 Bean 的生命周期执行自定义操作的接口,凡是实现该接口的 Bean,在初始化阶段都可以执行自定义的操作。

public interface InitializingBean {

	void afterPropertiesSet() throws Exception;
}

从 InitializingBean 源码中可以看出它有一个 afterPropertiesSet 方法,当一个 Bean 实现该接口时,在 Bean 的初始化阶段,会回调 afterPropertiesSet 方法,其初始化阶段具体指 Bean 设置完属性之后。

该接口使用方式如下:

@Component
public class Test implements InitializingBean { @Override
public void afterPropertiesSet() throws Exception {
System.out.println("Test 执行初始化");
}
}

定义启动类:

@SpringBootApplication
public class Main {
public static void main(String[] args) {
SpringApplication.run(Main.class, args);
}
}

结果:

...
2020-02-24 08:43:41.435 INFO 26193 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'httpTraceFilter' to: [/*]
2020-02-24 08:43:41.435 INFO 26193 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'webMvcMetricsFilter' to: [/*]
Test 执行初始化
2020-02-24 08:43:41.577 INFO 26193 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2020-02-24 08:43:41.756 INFO 26193 --- [ main] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@23529fee: startup date [Mon Feb 24 08:43:39 CST 2020]; root of context hierarchy
...

最终,afterPropertiesSet 方法被执行并打印输出语句。

3、BeanPostProcessor

BeanPostProcessor 和 InitializingBean 有点类似,也是可以在 Bean 的生命周期执行自定义操作,一般称之为 Bean 的后置处理器,不同的是,

BeanPostProcessor 可以在 Bean 初始化前、后执行自定义操作,且针对的目标也不同,InitializingBean 针对的是实现 InitializingBean 接口的 Bean,而 BeanPostProcessor 针对的是所有的 Bean。

public interface BeanPostProcessor {

	// Bean 初始化前调用
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
} // Bean 初始化后调用
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}

所有的 Bean 在初始化前、后都会回调接口中的 postProcessBeforeInitialization 和 postProcessAfterInitialization 方法,入参是当前正在初始化的 Bean 对象和 BeanName。值得注意的是 Spring 内置了非常多的 BeanPostProcessor ,以此来完善自身功能,这部分会在后面文章深入讨论。

这里通过自定义 BeanPostProcessor 来了解该接口的使用方式:

// 一般自定义的 BeanPostProcessor 命名格式都是以 BeanPostProcessor 为后缀。
@Component
public class TestBeanPostProcessor implements BeanPostProcessor { @Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println(beanName + " 初始化前执行操作");
return bean;
} @Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println(beanName + " 初始化后执行操作");
return bean;
}
}

启动类:

@SpringBootApplication
public class Main {
public static void main(String[] args) {
SpringApplication.run(Main.class);
}
}

结果:

...
2020-02-24 23:37:08.949 INFO 26615 --- [ main] com.loong.diveinspringboot.test.Main : No active profile set, falling back to default profiles: default
2020-02-24 23:37:08.994 INFO 26615 --- [ main] ConfigServletWebServerApplicationContext : Refreshing org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@2133814f: startup date [Mon Feb 24 23:37:08 CST 2020]; root of context hierarchy
2020-02-24 23:37:09.890 INFO 26615 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Multiple Spring Data modules found, entering strict repository configuration mode!
org.springframework.context.event.internalEventListenerProcessor 初始化前执行操作
org.springframework.context.event.internalEventListenerProcessor 初始化后执行操作
org.springframework.context.event.internalEventListenerFactory 初始化前执行操作
org.springframework.context.event.internalEventListenerFactory 初始化后执行操作
main 初始化前执行操作
main 初始化后执行操作
test 初始化前执行操作
Test 执行初始化
test 初始化后执行操作
...
org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration初始化前执行操作
2020-02-24 23:37:13.097 INFO 26615 --- [ main] o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup
2020-02-24 23:37:13.195 INFO 26615 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2020-02-24 23:37:13.207 INFO 26615 --- [ main] com.loong.diveinspringboot.test.Main : Started Main in 4.657 seconds (JVM running for 5.078)
...

可以看到,输出的结果中不仅包括自定义的 Test,还包括 Spring 内部的 Bean 。

BeanPostProcessor 使用场景其实非常多,因为它可以获取正在初始化的 Bean 对象,然后可以依据该 Bean 对象做一些定制化的操作,如:判断该 Bean 是否为某个特定对象、获取 Bean 的注解元数据等。事实上,Spring 内部也正是这样使用的,这部分也会在后面章节详细讨论。

4、BeanFactoryPostProcessor

BeanFactoryPostProcessor 是 Bean 工厂的后置处理器,一般用来修改上下文中的 BeanDefinition,修改 Bean 的属性值。

public interface BeanFactoryPostProcessor {

    // 入参是一个 Bean 工厂:ConfigurableListableBeanFactory。该方法执行时,所有 BeanDefinition 都已被加载,但还未实例化 Bean。
// 可以对其进行覆盖或添加属性,甚至可以用于初始化 Bean。
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}

BeanFactoryPostProcessor 源码非常简单,其提供了一个 postProcessBeanFactory 方法,当所有的 BeanDefinition 被加载时,该方法会被回调。值得注意的是,Spring 内置了许多 BeanFactoryPostProcessor 的实现,以此来完善自身功能。

这里,我们来实现一个自定义的 BeanFactoryPostProcessor:

@Component
public class TestBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
String beanNames[] = beanFactory.getBeanDefinitionNames();
for (String beanName : beanNames) {
BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);
System.out.println(beanDefinition);
}
}
}

主要是通过 Bean 工厂获取所有的 BeanDefinition 。

接着启动程序:

@SpringBootApplication
public class Main {
public static void main(String[] args) {
SpringApplication.run(Main.class);
}
}

结果:

2020-02-25 21:46:00.754  INFO 28907 --- [           main] ConfigServletWebServerApplicationContext : ...
2020-02-25 21:46:01.815 INFO 28907 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : ...
Root bean: class [org.springframework.context.annotation.ConfigurationClassPostProcessor]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null
Root bean: class [org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null
...
2020-02-25 21:46:04.926 INFO 28907 --- [ main] o.s.j.e.a.AnnotationMBeanExporter : ...
2020-02-25 21:46:04.989 INFO 28907 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : ...
2020-02-25 21:46:04.993 INFO 28907 --- [ main] com.loong.diveinspringboot.test.Main : ...

可以看到,BeanDefinition 正确输出,里面是一些 Bean 的相关定义,如:是否懒加载、Bean 的 Class 以及 Bean 的属性等。

5、ImportSelector

ImportSelector 是一个较为重要的扩展接口,通过该接口可动态的返回需要被容器管理的类,不过一般用来返回外部的配置类。可在标注 @Configuration 注解的类中,通过 @Import 导入 ImportSelector 来使用。

public interface ImportSelector {

	// 方法入参是注解的元数据对象,返回值是类的全路径名数组
String[] selectImports(AnnotationMetadata importingClassMetadata);
}

selectImports 方法返回的是类的全路径名。

自定义 ImportSelector:

public class TestImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) { if (importingClassMetadata.hasAnnotation("")) {
// 判断是否包含某个注解
} // 返回 Test 的全路径名,Test 会被放入到 Spring 容器中
return new String[]{"com.loong.diveinspringboot.test.Test"};
}
}

selectImports 方法中可以针对通过 AnnotationMetadata 对象进行逻辑判断,AnnotationMetadata 存储的是注解元数据信息,根据这些信息可以动态的返回需要被容器管理的类名称。

定义的 Test 类:

public class Test {
public void hello() {
System.out.println("Test -- hello");
}
}

这里,我们没有对 Test 标注 @Component 注解,所以,Test 不会自动加入到 Spring 容器中。

@SpringBootApplication
@Import(TestImportSelector.class)
public class Main {
public static void main(String[] args) {
SpringApplication springApplication = new SpringApplication();
ConfigurableApplicationContext run = springApplication.run(Main.class);
Test bean = run.getBean(Test.class);
bean.hello();
}
}

之后通过 @Import 导入自定义的 TestImportSelector ,前面也说过,@Import 一般配合 @Configuration 使用,而 @SpringBootApplication 中包含了 @Configuration 注解。之后,通过 getBean 方法从容器中获取 Test 对象,并调用 hello 方法。

2020-02-26 08:01:41.712  INFO 29546 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup
2020-02-26 08:01:41.769 INFO 29546 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2020-02-26 08:01:41.773 INFO 29546 --- [ main] com.loong.diveinspringboot.test.Main : Started Main in 4.052 seconds (JVM running for 4.534)
Test -- hello

最终,结果正确输出。

6、ImportBeanDefinitionRegistrar

该接口和 ImportSelector 类似,也是配合 @Import 使用,不过 ImportBeanDefinitionRegistrar 更为直接一点,它可以直接把 Bean 注册到容器中。

public interface ImportBeanDefinitionRegistrar {

	public void registerBeanDefinitions(
AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry);
}

入参除了注解元数据对象 AnnotationMetadata 外,还多了一个 BeanDefinitionRegistry 对象,在前面的文章讲过,该对象定义了关于 BeanDefinition 的一系列的操作,如:注册、移除、查询等。

自定义 ImportBeanDefinitionRegistrar:

public class TestRegistrar implements ImportBeanDefinitionRegistrar {
// 一般通过 AnnotationMetadata 进行业务判断,然后通过 BeanDefinitionRegistry 直接注册 Bean
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
RootBeanDefinition beanDefinition = new RootBeanDefinition(Test.class);
beanDefinition.setLazyInit(true);
registry.registerBeanDefinition(Test.class.getName(), beanDefinition);
}
}

这里,主要通过 BeanDefinitionRegistry 手动注册 Test 类的 BeanDefinition,并设置懒加载属性。

ImportSelector 和 ImportBeanDefinitionRegistrar 是实现 @Enable 模式注解的核心接口,而 @Enable 模式注解在 Spring、SpringBoot、SpringCloud 中被大量使用,其依靠这些注解来实现各种功能及特性,是较为重要的扩展接口,我们会在后面的文章中反复讨论,包括 ImportSelector 和 ImportBeanDefinitionRegistrar 是如何被 Spring 调用的、以及一些重要的 @Enable 注解实现。

值得注意的是,SpringBoot 外部化配置、自动装配特性就是通过 @Enable 注解配合 ImportSelector 和 ImportBeanDefinitionRegistrar 接口来实现的,这部分在前面的 SpringBoot 系列的文章中已经讨论过,感兴趣的同学可自行翻阅。

7、FactoryBean

FactoryBean 也是一种 Bean,不同于普通的 Bean,它是用来创建 Bean 实例的,属于工厂 Bean,不过它和普通的创建不同,它提供了更为灵活的方式,其实现有点类似于设计模式中的工厂模式和修饰器模式。

Spring 框架内置了许多 FactoryBean 的实现,它们在很多应用如(Spring的AOP、ORM、事务管理)及与其它第三框架(ehCache)集成时都有体现。

public interface FactoryBean<T> {
// 该方法会返回该 FactoryBean “生产”的对象实例,我们需要实现该方法以给出自己的对象实例化逻辑
T getObject() throws Exception; // Bean的类型
Class<?> getObjectType(); // 是否是单例
default boolean isSingleton() {
return true;
}
}

自定义 FactoryBean:

@Component
public class TestFactoryBean implements FactoryBean<Test> {
@Override
public Test getObject() throws Exception { // 这里可以灵活的创建 Bean,如:代理、修饰 return new Test();
} @Override
public Class<?> getObjectType() {
return null;
}
}

Test 类:

public class Test {
public void hello() {
System.out.println("Test -- hello");
}
}

启动类:

@SpringBootApplication
public class Main {
public static void main(String[] args) {
SpringApplication springApplication = new SpringApplication();
ConfigurableApplicationContext run = springApplication.run(Main.class);
Test bean = (Test) run.getBean("testFactoryBean");
bean.hello();
}
}

输出:

2020-02-27 23:16:00.334  INFO 32234 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2020-02-27 23:16:00.338 INFO 32234 --- [ main] com.loong.diveinspringboot.test.Main : Started Main in 3.782 seconds (JVM running for 4.187)
Test -- hello

可以看到,启动类中 getBean 的参数是 testFactoryBean ,从这可以看出,当容器中的 Bean 实现了 FactoryBean 后,通过 getBean(String BeanName) 获取到的 Bean 对象并不是 FactoryBean 的实现类对象,而是这个实现类中的 getObject() 方法返回的对象。如果想获取 FactoryBean 的实现类,需通过这种方式:getBean(&BeanName),在 BeanName 之前加上&。

8、ApplicationListener

ApplicationListener 是 Spring 实现事件机制的核心接口,属于观察者设计模式,一般配合 ApplicationEvent 使用。在 Spring 容器启动过程中,会在相应的阶段通过 ApplicationContext 发布 ApplicationEvent 事件,之后所有的 ApplicationListener 会被回调,根据事件类型,执行不同的操作。

public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {

	void onApplicationEvent(E event);
}

在 onApplicationEvent 方法中,通过 instanceof 判断 event 的事件类型。

自定义 ApplicationListener:

@Component
public class TestApplicationListener implements ApplicationListener {
@Override
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof TestApplicationEvent) {
TestApplicationEvent testApplicationEvent = (TestApplicationEvent) event;
System.out.println(testApplicationEvent.getName());
}
}
}

当自定义的 TestApplicationListener 被回调时,判断当前发布的事件类型是否是自定义的 TestApplicationEvent,如果是则输出事件名称。

自定义 TestApplicationEvent:

public class TestApplicationEvent extends ApplicationEvent {

    private String name;

    public TestApplicationEvent(Object source, String name) {
super(source);
this.name = name;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
}
}

启动类:

@SpringBootApplication
public class Main {
public static void main(String[] args) {
SpringApplication springApplication = new SpringApplication();
ConfigurableApplicationContext run = springApplication.run(Main.class);
run.publishEvent(new TestApplicationEvent(new Main(),"Test 事件"));
}
}

通过 ApplicationContext 发布 TestApplicationEvent 事件。当然也可以在业务代码中通过 ApplicationContextAware 获取 ApplicationContext 发布事件。

结果:

2020-02-27 08:37:10.972  INFO 30984 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup
2020-02-27 08:37:11.026 INFO 30984 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2020-02-27 08:37:11.029 INFO 30984 --- [ main] com.loong.diveinspringboot.test.Main : Started Main in 3.922 seconds (JVM running for 4.367)
Test 事件

ApplicationListener 也被 SpringBoot 进行扩展,来实现自身特定的事件机制。这部分也在前面的文章讨论过,感兴趣的同学可自行翻阅。

最后

Spring 的钩子接口就介绍到这,值得注意的是,Spring 的许多核心功能也是通过其内置的钩子接口来实现的,特别是一些核心注解,如:@Component 和 @Bean 的实现,这些都会在后面的文章一一讨论。

以上就是本章内容,如果文章中有错误或者需要补充的请及时提出,本人感激不尽。

Spring(七)核心容器 - 钩子接口的更多相关文章

  1. 【Spring】 Spring的核心容器

    Spring的核心容器 文章目录 Spring的核心容器 BeanFactory ApplicationContext 1.通过ClassPathXmlApplicationContext创建 2.通 ...

  2. Spring之核心容器bean

    摘要:Spring的核心容器实现了Ioc,其目 的是提供一种无侵入式的框架.在本文中,首先讲解了Spring的基础bean的相关知识,然后介绍了Spring是如何对bean进行管理的. 在Spring ...

  3. Spring的核心容器

    Spring框架的主要功能是通过其核心容器来实现的.Spring提供了2种核心容器:BeanFactory.ApplicationContext. BeanFactory BeanFactory是一个 ...

  4. spring的核心容器ApplicationContext

    //bean.xml配置文件 <?xml version="1.0" encoding="UTF-8"?><beans xmlns=" ...

  5. Spring学习总结(6)——Spring之核心容器bean

    一.Bean的基础知识 1.在xml配置文件中,bean的标识(id 和 name) id:指定在benafactory中管理该bean的唯一的标识.name可用来唯一标识bean 或给bean起别名 ...

  6. 初识Spring——Spring核心容器

    一. IOC和DI基础 IOC-Inversion of Control,译为控制反转,是一种遵循依赖倒置原则的代码设计思想. 所谓依赖倒置,就是把原本的高层建筑依赖底层建筑“倒置”过来,变成底层建筑 ...

  7. spring技术核心概念纪要

    一.背景 springframework 从最初的2.5版本发展至今,期间已经发生了非常多的修正及优化.许多新特性及模块的出现,使得整个框架体系显得越趋庞大,同时也带来了学习及理解上的困难. 本文阐述 ...

  8. spring MVC核心思想

    目录  一.前言二.spring mvc 核心类与接口三.spring mvc 核心流程图 四.spring mvc DispatcherServlet说明 五.spring mvc 父子上下文的说明 ...

  9. Asp.net 面向接口可扩展框架之核心容器(含测试代码下载)

    新框架的容器部分终于调通了!容器实在太重要了,所以有用了一个名词叫“核心容器”. 容器为什么那么重要呢?这个有必要好好说道说道. 1.首先我们从框架名称面向接口编程说起,什么是面向接口编程?(这个度娘 ...

随机推荐

  1. webpack进阶用法你都get到了么?

    如何消除无用代码:打包自己的私有js库:实现代码分割和动态import提升初次加载速度:配置eslint规范团队代码规范:打包异常抓捕你都get到了么? 摇树优化:Tree Shaking webpa ...

  2. 字典 pop

    1.pop(key) 删除键值对,返回value2.若字典中没有这个key,则返回None,也可以自定义3.可用作if条件判断 来源: rest framework 框架 Serializer que ...

  3. 外网主机远程ssh局域网Linux

    最近,公司有台配置极高的主机盒子(i7,32G,512G),组长让我装上kali,平时渗透测试时可以用,其余时间归我了,这么高配置的机器,怎么舍得让它吃灰呢 .所以我就去研究了一下,如何远程访问局域网 ...

  4. 【洛谷4424】[HNOI_AHOI2018]寻宝游戏(我也不知道括号里该写啥)

    题目 洛谷 4424 分析 感觉思路比较神仙. 对于按位与和按位或两种运算,显然每一位是独立的,可以分开考虑. 对于某一位,「与 \(0\)」会将这一位变成 \(0\),「或 \(1\)」会将这一位变 ...

  5. 20191216 GXOI 2019模拟赛 逼死强迫症

    题目传送门 分析: sb矩阵加速推一辈子... 想了1个小时,结果好像还和标准答案的方法不一样诶... 标算解法: 老套路,对于新加入的一列,考虑它与目前最后一列的关系 我们可以列出四种方案: 其中前 ...

  6. 谈谈模型融合之三 —— GBDT

    前言 本来应该是年后就要写的一篇博客,因为考完试后忙了一段时间课设和实验,然后回家后又在摸鱼,就一直没开动.趁着这段时间只能呆在家里来把这些博客补上.在之前的文章中介绍了 Random Forest ...

  7. widows 10 下解决在npm install python 环境报错的问题

    1.使用管理员打开cmd 2.安装 node-gyp; gyp是一种根据c++源代码编译的工具,node-gyp就是为node编译c++扩展的时候使用的编译工具. npm install -g nod ...

  8. Linux中软件安装包的格式

    一.Linux常用安装包及安装方法 1.安装包一般有四类: 1)tar包,如software-1.2.3-1.tar.gz.他是使用UNIX系统的打包工具tar打包的. 2)rpm包,如softwar ...

  9. java容器(一) Collection类框架图解

  10. C语言系列之实验楼笔记(一)

    创建C程序的几个过程: 1.编辑:创建和修改C程序的源代码 2.编译:编译器可以将源代码转成机器语言.linux 这些文件扩展名.o 3.链接:通过一次完成编译和链接 4.执行;运行程序 打开xfce ...