-
Spring 了解Bean的一生(生命周期)
2018-04-25 22:29:00该篇博客就来了解IoC容器下Bean的一生吧,也可以理解为bean的生命周期。 首先你需要知道的知识 在IoC容器启动之后,并不会马上就实例化相应的bean,此时容器仅仅拥有所有对象的BeanDefinition(Bean...该篇博客就来了解IoC容器下Bean的一生吧,也可以理解为bean的生命周期。
首先你需要知道的知识
在IoC容器启动之后,并不会马上就实例化相应的bean,此时容器仅仅拥有所有对象的BeanDefinition(BeanDefinition:是容器依赖某些工具加载的XML配置信息进行解析和分析,并将分析后的信息编组为相应的BeanDefinition)。只有当getBean()调用时才是有可能触发Bean实例化阶段的活动
为什么说有可能触发Bean实例化阶段?
因为当对应某个bean定义的getBean()方法第一次被调用时,不管是显示的还是隐式的,Bean实例化阶段才会被触发,第二次被调用则会直接返回容器缓存的第一次实例化完的对象实例(因为默认是singleton单例,当然,这里的情况prototype类型的bean除外)
该篇博客主要阐述
1、Bean的一生过程
2、Bean的后置处理器
一、Bean的一生过程
先来看以下的图(Bean的一生)
可以简述为以下九步
- 实例化bean对象(通过构造方法或者工厂方法)
- 设置对象属性(setter等)(依赖注入)
- 如果Bean实现了BeanNameAware接口,工厂调用Bean的setBeanName()方法传递Bean的ID。(和下面的一条均属于检查Aware接口)
- 如果Bean实现了BeanFactoryAware接口,工厂调用setBeanFactory()方法传入工厂自身
- 将Bean实例传递给Bean的前置处理器的postProcessBeforeInitialization(Object bean, String beanname)方法
- 调用Bean的初始化方法
- 将Bean实例传递给Bean的后置处理器的postProcessAfterInitialization(Object bean, String beanname)方法
- 使用Bean
- 容器关闭之前,调用Bean的销毁方法
先看一个最简单的一生(没有使用Bean的后置处理器)
Student.java
package com.linjie.cycle; import org.springframework.beans.factory.BeanNameAware; /** * @author LinJie * @Description:一个学生类(Bean),能体现其生命周期的Bean */ public class Student implements BeanNameAware { private String name; //无参构造方法 public Student() { super(); } /** 设置对象属性 * @param name the name to set */ public void setName(String name) { System.out.println("设置对象属性setName().."); this.name = name; } //Bean的初始化方法 public void initStudent() { System.out.println("Student这个Bean:初始化"); } //Bean的销毁方法 public void destroyStudent() { System.out.println("Student这个Bean:销毁"); } //Bean的使用 public void play() { System.out.println("Student这个Bean:使用"); } /* 重写toString * @see java.lang.Object#toString() */ @Override public String toString() { return "Student [name = " + name + "]"; } //调用BeanNameAware的setBeanName() //传递Bean的ID。 @Override public void setBeanName(String name) { System.out.println("调用BeanNameAware的setBeanName()..." ); } }
测试类
package com.linjie.cycle; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.AbstractApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; /** * 测试类 * @author LinJie * */ public class CycleTest { @Test public void test() { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); Student student = (Student) context.getBean("student"); //Bean的使用 student.play(); System.out.println(student); //关闭容器 ((AbstractApplicationContext) context).close(); } }
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- init-method:指定初始化的方法 destroy-method:指定销毁的方法 --> <bean id="student" class="com.linjie.cycle.Student" init-method="initStudent" destroy-method="destroyStudent"> <property name="name" value="LINJIE"></property> </bean> </beans>
控制台显示结果
可以在输出结果看出bean的一生,完全与之前的一生过程图相符(除了bean后置处理器部分),这里还需要提及的是在xml配置中的两个属性
- init-method:指定初始化的方法
- destroy-method:指定销毁的方法
说到init-method和destroy-method,当然也要提及一下在< beans>的属性
- default-init-method:为应用上下文中所有的Bean设置了共同的初始化方法
- default-destroy-method:为应用上下文中所有的Bean设置了共同的销毁方法
二、Bean的后置处理器
上面bean的一生其实已经算是对bean生命周期很完整的解释了,然而bean的后置处理器,是为了对bean的一个增强
用法
分别在Bean的初始化前后对Bean对象提供自己的实例化逻辑
- 实现BeanPostProcessor接口 - postProcessBeforeInitialization方法 - postProcessAfterInitialization方法
接上面的Student Demo
Student.java
package com.linjie.cycle; import org.springframework.beans.factory.BeanNameAware; /** * @author LinJie * @Description:一个学生类(Bean),能体现其生命周期的Bean */ public class Student implements BeanNameAware { private String name; //无参构造方法 public Student() { super(); } /** 设置对象属性 * @param name the name to set */ public void setName(String name) { System.out.println("设置对象属性setName().."); this.name = name; } //Bean的初始化方法 public void initStudent() { System.out.println("Student这个Bean:初始化"); } //Bean的销毁方法 public void destroyStudent() { System.out.println("Student这个Bean:销毁"); } //Bean的使用 public void play() { System.out.println("Student这个Bean:使用"); } /* 重写toString * @see java.lang.Object#toString() */ @Override public String toString() { return "Student [name = " + name + "]"; } //调用BeanNameAware的setBeanName() //传递Bean的ID。 @Override public void setBeanName(String name) { System.out.println("调用BeanNameAware的setBeanName()..." ); } }
MyBeanPostProcessor.java(实现BeanPostProcessor接口)
package com.linjie.cycle; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanPostProcessor; /** * bean的后置处理器 * 分别在bean的初始化前后对bean对象提供自己的实例化逻辑 * postProcessAfterInitialization:初始化之后对bean进行增强处理 * postProcessBeforeInitialization:初始化之前对bean进行增强处理 * @author LinJie * */ public class MyBeanPostProcessor implements BeanPostProcessor { //对初始化之后的Bean进行处理 //参数:bean:即将初始化的bean //参数:beanname:bean的名称 //返回值:返回给用户的那个bean,可以修改bean也可以返回一个新的bean @Override public Object postProcessAfterInitialization(Object bean, String beanname) throws BeansException { Student stu = null; System.out.println("对初始化之后的Bean进行处理,将Bean的成员变量的值修改了"); if("name".equals(beanname) || bean instanceof Student) { stu = (Student) bean; stu.setName("Jack"); } return stu; } //对初始化之前的Bean进行处理 //参数:bean:即将初始化的bean //参数:beanname:bean的名称 //返回值:返回给用户的那个bean,可以修改bean也可以返回一个新的bean @Override public Object postProcessBeforeInitialization(Object bean, String beanname) throws BeansException { System.out.println("对初始化之前的Bean进行处理,此时我的名字"+bean); return bean; } }
测试类
package com.linjie.cycle; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.AbstractApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; /** * 测试类 * @author LinJie * */ public class CycleTest { @Test public void test() { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); Student student = (Student) context.getBean("student"); //Bean的使用 student.play(); System.out.println(student); //关闭容器 ((AbstractApplicationContext) context).close(); } }
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- init-method:指定初始化的方法 destroy-method:指定销毁的方法 --> <bean id="student" class="com.linjie.cycle.Student" init-method="initStudent" destroy-method="destroyStudent"> <property name="name" value="LINJIE"></property> </bean> <!-- 配置bean的后置处理器,不需要id,IoC容器自动识别是一个BeanPostProcessor --> <bean class="com.linjie.cycle.MyBeanPostProcessor"></bean> </beans>
控制台显示结果
可以在applicationContext.xml中看到配置Bean后置处理器,不需要ID,只需要其全类名,因为IoC容器自动识别一个BeanPostProcessor
#####在控制台显示结果可以看出,Bean的后置处理器强大之处,可以对Bean实现自己想要做的事情,比如我这里的Demo就是在postProcessAfterInitialization方法中将成员变量name偷偷修改了,最后输出的就是偷偷修改之后的值
好了以上就是bean的一生,在控制台下将bean的一生映射出来,对理解bean的一生(生命周期)更加直观咯
参考
《Spring揭秘》
《Spring IN ACTION》 -
vue生命周期
2020-09-28 09:18:11随着对 vue 的不断了解,会越来越发现它生命周期的重要性,只有了解了它的生命周期,才能在开发项目的时候在逻辑上的很好的判断什么时候该发生什么事件,即很好的控制页面。 一、什么是 vue 生命周期 Vue 实例从...随着对 vue 的不断了解,会越来越发现它生命周期的重要性,只有了解了它的生命周期,才能在开发项目的时候在逻辑上的很好的判断什么时候该发生什么事件,即很好的控制页面。
一、什么是 vue 生命周期
Vue 实例从创建到销毁的过程,就是生命周期。也就是从开始创建、初始化数据、编译模板、挂载Dom→渲染、更新→渲染、卸载等一系列过程,我们称这是 Vue 的生命周期。下面是官网中的生命周期照片
二、生命周期函数
Vue 的生命周期总共分为8个阶段:创建前/后,载入前/后,更新前/后,销毁前/后。
1、beforeCreate(创建前)
表示实例完全被创建出来之前,vue 实例的挂载元素$el和数据对象 data 都为 undefined,还未初始化。
2、created(创建后)
数据对象 data 已存在,可以调用 methods 中的方法,操作 data 中的数据,但 dom 未生成,$el 未存在 。
3、beforeMount(挂载前)
vue 实例的 $el 和 data 都已初始化,挂载之前为虚拟的 dom节点,模板已经在内存中编辑完成了,但是尚未把模板渲染到页面中。data.message 未替换。
4、mounted(挂载后)
vue 实例挂载完成,data.message 成功渲染。内存中的模板,已经真实的挂载到了页面中,用户已经可以看到渲染好的页面了。实例创建期间的最后一个生命周期函数,当执行完 mounted 就表示,实例已经被完全创建好了,DOM 渲染在 mounted 中就已经完成了。
5、beforeUpdate(更新前)
当 data 变化时,会触发beforeUpdate方法 。data 数据尚未和最新的数据保持同步。
6、updated(更新后)
当 data 变化时,会触发 updated 方法。页面和 data 数据已经保持同步了。
7、beforeDestory(销毁前)
组件销毁之前调用 ,在这一步,实例仍然完全可用。
8、destoryed(销毁后)
组件销毁之后调用,对 data 的改变不会再触发周期函数,vue 实例已解除事件监听和 dom绑定,但 dom 结构依然存在。
-
flutter 生命周期
2018-09-13 22:20:26前言:生命周期是一个组件加载到卸载的整个周期,熟悉生命周期可以让我们在合适的时机做该做的事情, flutter中的State生命周期和android以及React Native的生命周期类似。 先看一张生命周期的流程图: 大致...前言:生命周期是一个组件加载到卸载的整个周期,熟悉生命周期可以让我们在合适的时机做该做的事情,
flutter中的State生命周期和android以及React Native的生命周期类似。先看一张生命周期的流程图:
大致可以分为3个阶段:- 初始化
- 状态变化
- 组件移除
初始化
State初始化时会依次执行 : 构造函数 > initState > didChangeDependencies > Widget build , 此时页面加载完成。
然后我们看一下每个函数的意义:
构造函数
调用次数:1次
这个函数严格意义上来讲不属于生命周期的一部分,因为这个时候State的widget属性为空,无法在构造函数中访问widget的属性 。但是构造函数必然是要第一个调用的。可以在这一部分接收前一个页面传递过来的数据。
initState
Called when this object is inserted into the tree.
调用次数:1次
当插入渲染树的时候调用,这个函数在生命周期中只调用一次。这里可以做一些初始化工作,比如初始化State的变量。
didChangeDependencies
Called when a dependency of this [State] object changes.
- 初始化时,在initState()之后立刻调用
- 当依赖的InheritedWidget rebuild,会触发此接口被调用
这个函数会紧跟在initState之后调用,并且可以调用BuildContext.inheritFromWidgetOfExactType,那么BuildContext.inheritFromWidgetOfExactType的使用场景是什么呢?最经典的应用场景是
new DefaultTabController(length: 3, child: new TabBar( tabs: [ "主页","订单","我的" ] .map( (data)=>new Text(data) ).toList(),
TabBar本来需要定义一个TabController,但是在外面套一层DefaultTabController就不需要定义TabContrller了,看下源码:
@override void didChangeDependencies() { super.didChangeDependencies(); _updateTabController(); _initIndicatorPainter(); } void _updateTabController() { final TabController newController = widget.controller ?? DefaultTabController.of(context); ... }
注意到这里DefaultTabController.of(context)
static TabController of(BuildContext context) { final _TabControllerScope scope = context.inheritFromWidgetOfExactType(_TabControllerScope); return scope?.controller; }
实际上就是调用BuildContext.inheritFromWidgetOfExactType,也就说在didChangeDependencies中,可以跨组件拿到数据。
#运行时
build
调用次数:多次
初始化之后开始绘制界面,当setState触发的时候会再次被调用
didUpdateWidget
Called whenever the widget configuration changes.
祖先节点rebuild widget时调用 .当组件的状态改变的时候就会调用didUpdateWidget.
理论上setState的时候会调用,但我实际操作的时候发现只是做setState的操作的时候没有调用这个方法。而在我改变代码hot reload时候会调用 didUpdateWidget 并执行 build…
实际上这里flutter框架会创建一个新的Widget,绑定本State,并在这个函数中传递老的Widget。
这个函数一般用于比较新、老Widget,看看哪些属性改变了,并对State做一些调整。需要注意的是,涉及到controller的变更,需要在这个函数中移除老的controller的监听,并创建新controller的监听。
组件移除
组件移除,例如页面销毁的时候会依次执行:deactivate > dispose
deactivate
Called when this object is removed from the tree.
在dispose之前,会调用这个函数。实测在组件可见状态变化的时候会调用,当组件卸载时也会先一步dispose调用。
dispose
Called when this object is removed from the tree permanently.
调用次数:1次
一旦到这个阶段,组件就要被销毁了,这个函数一般会移除监听,清理环境。
##reassemble
hot reload调用名称 状态 initState 插入渲染树时调用,只调用一次 didChangeDependencies state依赖的对象发生变化时调用 didUpdateWidget 组件状态改变时候调用,可能会调用多次 build 构建Widget时调用 deactivate 当移除渲染树的时候调用 dispose 组件即将销毁时调用 实际场景
假设我们从A页面跳转到B页面, 那么A,B页面的生命周期会是怎样的呢?
B页面进入初始化状态,依次执行4个函数:
构造函数 > initState > didChangeDependencies > Widget build
, 此时页面加载完成,进入运行态。
此时A页面依次执行deactivate > build
函数。注意 此时A页面并未卸载。然后我们假设B页面只有一个按钮,点击B页面中的按钮,改变按钮的文字,会执行widget的
build
方法 ,(理论上也应该执行didUpdateWidget
,但我这里没有)。这时,我们点击返回键从B页面返回到A页面。
A页面重新显示,B页面开始卸载。
那么A先执行deactivate > build
, 然后B页面依次执行:deactivate > dispose
。
此时A页面进入运行态,B页面移除。本次示例B页面代码:
/* * Created by 李卓原 on 2018/9/13. * email: zhuoyuan93@gmail.com * */ import 'package:flutter/material.dart'; class NewsDetailPage extends StatefulWidget { @override State<StatefulWidget> createState() => NewsDetailState(); } class NewsDetailState extends State<NewsDetailPage> { int text = 1; NewsDetailState() { print('构造函数'); } @override void initState() { print('init state'); super.initState(); } @override void didChangeDependencies() { print('didChangeDependencies'); super.didChangeDependencies(); } @override Widget build(BuildContext context) { print('widget build'); return Scaffold( body: Center( child: _loading(), ), appBar: AppBar( title: Text('咨询详情'), ), ); } @override void didUpdateWidget(NewsDetailPage oldWidget) { print('组件状态改变:didUpdateWidget'); super.didUpdateWidget(oldWidget); } @override void deactivate() { print('移除时:deactivate'); super.deactivate(); } @override void dispose() { print('移除时:dispose'); super.dispose(); } //预加载布局 Widget _loading() { return Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ CircularProgressIndicator( strokeWidth: 1.0, ), Container( child: Text("正在加载"), margin: EdgeInsets.only(top: 10.0), ) ], ); } }
Tips:
下面内容来自咸鱼技术团队.
-
当ListView中的item滚动出可显示区域的时候,item会被从树中remove掉,此item子树中所有的state都会被dispose,state记录的数据都会销毁,item滚动回可显示区域时,会重新创建全新的state、element、renderobject
-
使用hot reload功能时,要特别注意state实例是没有重新创建的,如果该state中存在一下复杂的资源更新需要重新加载才能生效,那么需要在reassemble()添加处理,不然当你使用hot reload时候可能会出现一些意想不到的结果,例如,要将显示本地文件的内容到屏幕上,当你开发过程中,替换了文件中的内容,但是hot reload没有触发重新读取文件内容,页面显示还是原来的旧内容.
-
didChangeDependencies有两种情况会被调用。
-
创建时候在initState 之后被调用
-
在依赖的InheritedWidget发生变化的时候会被调用
-
正常的退出流程中会执行deactivate然后执行dispose。但是也会出现deactivate以后不执行dispose,直接加入树中的另一个节点的情况。
-
这里的状态改变包括两种可能:1.通过setState内容改变 2.父节点的state状态改变,导致孩子节点的同步变化。
App生命周期
需要指出的是如果想要知道App的生命周期,那么需要通过WidgetsBindingObserver的didChangeAppLifecycleState 来获取。通过该接口可以获取是生命周期在AppLifecycleState类中。常用状态包含如下几个:
名称 状态 resumed 可见并能响应用户的输入 inactive 处在并不活动状态,无法处理用户响应 paused 不可见并不能响应用户的输入,但是在后台继续活动中 一个实际场景中的例子:
在不考虑suspending的情况下:从后台切入前台生命周期变化如下: AppLifecycleState.inactive->AppLifecycleState.resumed;
从前台压后台生命周期变化如下: AppLifecycleState.inactive->AppLifecycleState.paused;
class _MyWalletScreenState extends State<MyWalletScreen> with WidgetsBindingObserver { @override void initState() { super.initState(); WidgetsBinding.instance.addObserver(this); } @override void dispose() { WidgetsBinding.instance.removeObserver(this); super.dispose(); } void didChangeAppLifecycleState(AppLifecycleState state) async { if (state == AppLifecycleState.resumed) { getData(); } } }
记得注册和移除监听。
-
-
深入理解maven构建生命周期和各种plugin插件
2018-05-15 15:37:48本博文不会长篇大论的讨论生命周期的概念,而是从各种plugin的实际功能和应用出发,来讨论maven的实际应用,说得通透一点,生命周期(lifecycle)可以理解成由各种plugin按照一定的顺序执行来完成java项目清理、...鄙人的新书《Elasticsearch权威指南》正式出版发行,欢迎购买!本书由华为、中兴高级技术专家全面审读并撰序,助您挑战百万年薪 购书链接:
《Elasticsearch权威指南》
欢迎关注鄙人公众号,技术干货随时看!
技术交流qq群: 659201069鄙人的新书《elasticsearch7完全开发指南》,欢迎订阅!
https://wenku.baidu.com/view/8ff2ce94591b6bd97f192279168884868762b8e7
《kibana权威指南》
https://wenku.baidu.com/view/24cfee1ce43a580216fc700abb68a98270feac21
本博文不会长篇大论的讨论生命周期的概念,而是从各种plugin的实际功能和应用出发,来讨论maven的实际应用,说得通透一点,生命周期(lifecycle)可以理解成由各种plugin按照一定的顺序执行来完成java项目清理、编译、打包、测试、布署等整个项目的流程的一个过程。
生命周期(lifecycle)由各个阶段组成,每个阶段由maven的插件plugin来执行完成。生命周期(lifecycle)主要包括clean、resources、complie、install、package、testResources、testCompile等,其中带test开头的都是用业编译测试代码或运行单元测试用例的。总揽生命周期(lifecycle)
一般构建项目时执行的最常用的命领是mvn clean install,如果是IDE就是点对应的按纽其实还是调的mvn命令,除非你使用的IDE内嵌的maven(不推荐使用内嵌的maven)。下周通过一个具体的实例来详细了解执行mvn clean install这条命令背后,maven为我们做了哪些事情。我们有一个工程,工程结构如下图所示,这个工程非常简单,只有两个类,Hello类和对应的测试类HelloWorldTest,
Hello类和对应的测试类HelloWorldTest,代码如下
package com.feiniu.bigdata.helloworld; import com.feiniu.bigdata.hello.Hello; import com.feiniu.bigdata.main.Main; import junit.framework.TestCase; import org.junit.Test; public class HelloWorldTest { @Test public void testSayHello(){ Hello hello = new Hello(); String result = hello.sayHello(); TestCase.assertEquals("Hello world",result); } }
package com.feiniu.bigdata.hello; public class Hello { public String sayHello() { return "Hello world"; } public static void main(String[] args) { System.out.println(new Hello().sayHello()); } }
pom文件也很简单如下所示:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.feiniu.bigdata</groupId> <artifactId>fn.program</artifactId> <version>1.0-SNAPSHOT</version> <packaging>jar</packaging> <name>fn program</name> <description>This is a program to tesc new function of jdk8</description> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.3</version> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> </plugins> </build> <dependencies> <!-- https://mvnrepository.com/artifact/junit/junit --> <!-- test只对test代码有效,主代码引用会报错,compile对主代码和测试代码都有效 --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> </dependencies> </project>
到项目根目录下执行mvn clean install 对应的输出如下图所示
由上图可知,各个插件的执行顺序一般是:1:clean、2:resources、3:compile、4:testResources、5:testCompile、6:test、7:jar、8:install。在图中标记的地方每一行都是由冒号分隔的,前半部分是对应的插件,后半部分是插件的执行目标也就是插件执行产生的结果。现在我们来看下上面的pom文件,我们如配置了maven-compiler-plugin这个插件,其它的插件没有配置,但最后项目构建成功,说明maven内置的各种插件,如果pom中没有配置就调用默认的内置插件,如果pom中配置了就调用配置的插件。到此我们理解maven的构建过程或者有更多的人称是打包,就是由各种插件按照一定的顺序执行来完成项目的编译,单元测试、打包、布署的完成。各种插件的执行过程也就构成的maven的生命周期(lifecycle)。生命周期(lifecycle)各个阶段并不是独立的,可以单独执行如mvn clean,也可以一起执行如mvn clean install。而且有的mvn命令其是包括多个阶段的,如mvn compile其是包括了resources和compile两个阶段。下面分别来分析各个阶段需要的插件和输出的结果
clean插件maven-clean-plugin:2.5
clean阶段是独立的一个阶段,功能就是清除工程目前下的target目录,对应的插件是 maven-clean-plugin:2.5,2.5是版本号,可以使用maven内置的插件,当然也可以自己在pom中配置,配置方式和上面所说的maven-compiler-plugin配置方式一样。下面看下mvn执行前后工程目录下的输出对比
resources插件maven-resources-plugin:2.6
resource插件的功能就是把项目需要的配置文件拷贝到指定的目当,默认是拷贝src\main\resources目录下的件到classes目录下,当然可以自己来配置源目录和输出目录。resources插件一般不单独执行,complie插件执行时会先调用resources插件。配置示例如下:
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-resources-plugin</artifactId> <version>2.6</version> <executions> <execution> <id>copy-resources</id> <!-- 在default生命周期的 validate阶段就执行resources插件的copy-resources目标 --> <phase>validate</phase> <goals> <goal>copy-resources</goal> </goals> <configuration> <!-- 指定resources插件处理资源文件到哪个目录下 --> <outputDirectory>${project.build.outputDirectory}</outputDirectory> <!-- 也可以用下面这样的方式(指定相对url的方式指定outputDirectory) <outputDirectory>target/classes</outputDirectory> --> <!-- 待处理的资源定义 --> <resources> <resource> <!-- 指定resources插件处理哪个目录下的资源文件 --> <directory>src/main/${deploy.env}/applicationContext.xml</directory> <!-- 指定不需要处理的资源 <excludes> <exclude>WEB-INF/*.*</exclude> </excludes> --> <!-- 是否对待处理的资源开启过滤模式 (resources插件的copy-resources目标也有资源过滤的功能,这里配置的 这个功能的效果跟<build><resources><resource>下配置的资源过滤是一样的,只不过可能执行的阶段不一样, 这里执行的阶段是插件指定的validate阶段,<build><resources><resource>下的配置将是在resources插件的resources目标执行时起作用(在process-resources阶段)) --> <filtering>false</filtering> </resource> </resources> </configuration> <inherited></inherited> </execution> </executions> </plugin>
compile插件maven-compiler-plugin
compile插件执行时先调用resouces插件,功能就是把src\mainjava源码编译成字节码生成class文件,并把编译好的class文件输出到target\classes目录下。下面看执行结果:
单元测试所用插件
单元测试所用的compile和resources插件和主代码是相同的,但执行的目标不行,目标estCompile和testResources是把src\test\java下的代码编译成字节码输出到target\test-classes,同时把src\test\resources下的配置文件拷贝到target\test-classes。看下面的输出:
插件maven-surefire-plugin:2.12.4是执行单元测试类的,在本例中就是运行HelloWorldTest.testSayHello()方法,如果单测试不通行,构建会失败,在编译正式的项目时可以使用mvn -Dmaven.test.skip=true 来跳过测试类的编译和运行过程。mvn test可以单独执行,但是这个命令其实是包括了resources、compile、testResources、testCompile、test这几个阶段,如下图所示:
打包插件
这个插件是把class文件、配置文件打成一个jar(war或其它格式)包。依赖包是不在jar里面的,需要建立lib目录,且jar和lib目录在同级目录。常用的打包插件有maven-jar-plugin、maven-assembly-plugin、maven-shade-plugin三种,下面分别介绍下各自己pom配置和使用特点。
maven-jar-plugin
可执行jar与依赖包是分开,需建立lib目录里来存放需要的j依赖包,且需要jar和lib目录在同级目录<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <version>2.6</version> <configuration> <archive> <manifest> <addClasspath>true</addClasspath> <classpathPrefix>lib/</classpathPrefix> <mainClass>com.xxx.xxxService</mainClass> </manifest> </archive> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-dependency-plugin</artifactId> <version>2.10</version> <executions> <execution> <id>copy-dependencies</id> <phase>package</phase> <goals> <goal>copy-dependencies</goal> </goals> <configuration> <outputDirectory>${project.build.directory}/lib</outputDirectory> </configuration> </execution> </executions> </plugin>
maven-assembly-plugin
这个插件可以把所有的依赖包打入到可执行jar包。但是该插件有个bug会缺失spring的xds文件,导致无法运行jar,同时如果同级目录还有其它可执行jar文件依赖可能会产生冲突。
<plugin> <artifactId>maven-assembly-plugin</artifactId> <configuration> <descriptorRefs> <descriptorRef>jar-with-dependencies</descriptorRef> </descriptorRefs> <archive> <manifest> <mainClass>com.xxx.xxxService</mainClass> </manifest> </archive> </configuration> <executions> <execution> <id>make-assembly</id> <phase>package</phase> <goals> <goal>single</goal> </goals> </execution> </executions> </plugin>
maven-shade-plugin
所有的依赖包打入到可执行jar包,如果同级目录有其它可执行jar,依赖可能会产生冲突,且运行jar时,有时会出现SF、DSA、RSA文件冲突的提示,需要排除META-INF目录下的文件。
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>2.4.3</version> <executions> <execution> <phase>package</phase> <goals> <goal>shade</goal> </goals> <configuration> <filters> <filter> <artifact>*:*</artifact> <excludes> <exclude>META-INF/*.SF</exclude> <exclude>META-INF/*.DSA</exclude> <exclude>META-INF/*.RSA</exclude> </excludes> </filter> </filters> <transformers> <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer"> <resource>META-INF/spring.handlers</resource> </transformer> <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer"> <resource>META-INF/spring.schemas</resource> </transformer> <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer"> <resource>META-INF/spring.tooling</resource> </transformer> <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> <mainClass>com.xxx.xxxInvoke</mainClass> </transformer> </transformers> <minimizeJar>true</minimizeJar> <shadedArtifactAttached>true</shadedArtifactAttached> </configuration> </execution> </executions> </plugin>
发布插件maven-install-plugin
发布插件的功能就是把构建好的artifact部署到本地仓库,还有一个deploy插件是将构建好的artifact部署到远程仓库。
-
Servlet的生命周期
2019-06-02 17:36:53Servlet的生命周期 servlet的生命周期就是从servlet出现到销毁的全过程。主要分为以下几个阶段: 加载类—>实例化(为对象分配空间)—>初始化(为对象的属性赋值)—>请求处理(服务阶段)—>销毁 服务器启动... -
浅析微信小程序生命周期之应用生命周期
2020-05-08 23:41:43微信小程序生命周期可分为应用生命周期、页面生命周期和组件生命周期,本文结合微信官方文档浅析微信小程序的应用生命周期。从注册一个小程序生命周期开始讲起,到一些关于开发的小经验。 -
什么叫生命周期,servlet的生命周期?jsp的生命周期?
2018-06-04 16:49:07什么叫生命周期,servlet的生命周期?jsp的生命周期?生命周期:就是类的产生到销毁的过程。servlet的生命周期:加载并实例化 –> 初始化 –> 应用阶段(请求处理) –> 销毁创建 Servlet 实例... -
php及php变量的生命周期、Laravel生命周期、Yii2生命周期、ThinkPHP生命周期
2018-06-09 23:07:56一、php生命周期(5块) 模块初始化阶段 --- php_module_startup() 请求初始化阶段 --- php_request_startup() 执行脚本阶段 --- php_execute_script() 请求关闭阶段 --- php_request_shutdown() 模块关闭阶段 --- ... -
项目生命周期和产品生命周期的不同
2019-05-07 09:02:461.项目生命周期的阶段之间可能相互交叉,而产品生命周期的阶段通常不相互交叉; 项目生命周期:项目初始->项目计划->项目执行控制->项目结束; 产品生命周期:投入期->成长期->饱和期->衰退期;... -
微信小程序生命周期、页面生命周期、组件生命周期
2019-11-06 15:30:351. 生命周期 App(全局) 位置:项目根目录app.js文件 App({ onLaunch (options) { // console.log('小程序初始化') }, onShow(options) { console.log('监听小程序启动或切前台') }, onHide() { ... -
vue生命周期钩子,vue生命周期钩子,vue生命周期钩子
2018-07-14 14:53:35vue 的生命周期11个钩子函数是按照以下的顺序来的 :(不可逆转哦,第11个除外) 一. 组件创建前后 1.beforeCreate 2.created 如,写一个子组件,然后挂在到父组件,在子组件中,console.log 子组件中的 data... -
Vue的生命周期钩子函数介绍
2019-05-11 22:45:23Vue的生命周期钩子函数介绍 vue生命周期共分为四个阶段 一:实例创建 二:DOM渲染 三:数据更新 四:销毁实例 共有八个基本钩子函数 1.beforeCreate --创建前 触发的行为:vue实例的挂载元素$el和数据对象data都为... -
vue生命周期函数、react生命周期函数、微信小程序生命周期函数、uni-app生命周期函数,简介及图示
2020-10-26 17:21:58vue生命周期函数 beforeCreate (创建前) created (创建后) beforeMount (挂载前) mounted (挂载后) beforeUpdate (数据更新前) updated (数据更新后) beforeDestroy (销毁前) destroyed (销毁后) 详情传送门 ... -
vue生命周期和react生命周期对比。
2019-07-06 18:04:03指的是组件从初始化开始到结束的过程 或者是生命周期是描述组件从开始到结束的过程,每个组件都具有生命周期,都对组件通过生命周期给予的钩子函数进行管理。 钩子函数 指的是系统某些状态和参数发生改变的时候,... -
[PMI]如何理解预测型生命周期、迭代和增量型生命周期和适应型生命周期?
2020-07-02 08:19:38如何理解预测型生命周期、迭代和增量型生命周期和适应型生命周期?预测性生命周期迭代和增量型生命周期适应性生命周期(变化驱动方法或敏捷方法) 预测性生命周期 预测性生命周期在生命周期的特点是确定性(项目开发... -
Activity 生命周期详解与异常情况生命周期
2019-06-30 20:51:43博主声明: 转载请在开头附加本文链接及作者信息,并标记为转载。... 在学习 Android 时候,通常一开始学习的都是它的生命周期,谁让我们第一个创建的就是 MainActivity 类呢。学习 Activity 就要从它... -
如何理解预测型生命周期、迭代和增量型生命周期和适应型生命周期?
2020-02-04 09:27:57预测性生命周期在生命周期的特点是确定性(项目开发时间确定、项目开发成本确定),成熟性(公司的产品已经很成熟了),规模性(项目已经具有一定规模了),可以尽早时间确定项目范围及所需的时间、成本。... -
理解Fragment生命周期
2012-11-29 14:33:01官网帮助文档链接: ... 主要看两张图,和跑代码 一,Fragment的生命周 二,与Activity生命周期的对比 场景演示 : 切换到该Fragment 11-29 14:26:35.095: D/AppListFragmen -
Vue生命周期详解
2020-06-25 11:19:34一、生命周期流程图详解 1.beforeCreate、Created 2.编辑模板过程 3.beforeMount、Mounted 4.beforeUpdate、Updated 5.beforeDestroy、Destroyed 二、生命周期代码 1.父子组件加载生命周期 2.父子组件更新... -
Uni-app页面生命周期和应用生命周期
2019-06-13 09:54:51Uni-app页面生命周期和应用生命周期 (V1.00版本)2019-6-13 学习任何框架必须将其生命周期了然于胸. uni-app支持如下页面生命周期函数: onLoad 监听页面加载,其参数为上个页面传递的数据,参数类型为object(用于... -
Vue生命周期
2019-06-06 15:36:07什么是 Vue 生命周期? Vue 实例从创建到销毁的过程,就是生命周期。从开始创建、初始化数据、编译模板、挂载 DOM -> 渲染、更新 -> 渲染、销毁等一系列过程,称之为 Vue 的生命周期。 Vue 有几个生命周期,... -
Spring中bean的作用域与生命周期
2017-06-17 22:29:182、bean的生命周期 Spring中Bean的实例化过程: Bean的生命周期: Bean实例生命周期的执行过程如下: Spring对bean进行实例化,默认bean是单例; Spring对bean进行依赖注入; 如果bean实现了BeanNameAware接口,... -
uniapp api学习页面生命周期,应用生命周期
2019-04-04 15:32:04生命周期,有页面生命周期,这个应用生命周期 相当于一个人从生到死有什么 生命周期可以利用很多 运行顺利 onLoad :({ }); onShow: ({ }); 当用户操作的时候会自动触发相应函数 onReady: ({}); onUnload: ({});... -
彻底理解vue的钩子函数,vue的生命周期理解,什么是vue的生命周期,钩子函数
2018-10-17 22:32:02使用vue框架,需要在合适的时机做合适的事情,了解了vue对象的生命周期和钩子函数,才能知道,哪些事情应该咋哪个函数里做。 一、vue的生命周期的理解 生命周期 用人举例说明: 生命周期就是一个人的一生,此处... -
react的生命周期钩子函数
2019-04-22 08:23:35掌握单词后会更好理解生命周期: constructor ------构造函数 component ------组件 will ------将要 get ------得到 default ------默认值 initial ------最初的 unsafe ... -
Servlet生命周期
2019-03-05 20:14:55Servlet生命周期 -
java对象生命周期和类生命周期
2018-01-05 15:04:13java对象生命周期对象的整个生命周期大致可以分为7个阶段:创建阶段(Creation)、应用阶段(Using)、不可视阶段(Invisible)、不可到达阶段(Unreachable)、可收集阶段(Collected)、终结阶段(Finalized)与... -
flutter 页面 生命周期,APP应用的生命周期
2019-08-17 11:29:271.页面生命周期 StatelessWidget只有createElement和build的生命周期 StatefulWidget: 初始化周期: createState,initState 更新期间: didChangeDependencies,build, didUpdateWidget 销毁期: ...