maven resource解释

Resources

Another feature of build elements is specifying where resources exist within your project. Resources are not (usually) code. They are not compiled, but are items meant to be bundled within your project or used for various other reasons, such as code generation.

For example, a Plexus project requires a configuration.xml file (which specifies component configurations to the container) to live within the META-INF/plexus directory. Although we could just as easily place this file within src/main/resources/META-INF/plexus, we want instead to give Plexus its own directory of src/main/plexus. In order for the JAR plugin to bundle the resource correctly, you would specify resources similar to the following:

  1. <project xmlns="http://maven.apache.org/POM/4.0.0"
  2. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
  4. https://maven.apache.org/xsd/maven-4.0.0.xsd">
  5. <build>
  6. ...
  7. <resources>
  8. <resource>
  9. <targetPath>META-INF/plexus</targetPath>
  10. <filtering>false</filtering>
  11. <directory>${basedir}/src/main/plexus</directory>
  12. <includes>
  13. <include>configuration.xml</include>
  14. </includes>
  15. <excludes>
  16. <exclude>**/*.properties</exclude>
  17. </excludes>
  18. </resource>
  19. </resources>
  20. <testResources>
  21. ...
  22. </testResources>
  23. ...
  24. </build>
  25. </project>
  • resources: is a list of resource elements that each describe what and where to include files associated with this project.
  • targetPath: Specifies the directory structure to place the set of resources from a build. Target path defaults to the base directory. A commonly specified target path for resources that will be packaged in a JAR is META-INF.
  • filtering: is true or false, denoting if filtering is to be enabled for this resource. Note, that filter *.properties files do not have to be defined for filtering to occur – resources can also use properties that are by default defined in the POM (such as ${project.version}), passed into the command line using the “-D” flag (for example, “-Dname=value“) or are explicitly defined by the properties element. Filter files were covered above.
  • directory: This element’s value defines where the resources are to be found. The default directory for a build is ${basedir}/src/main/resources.
  • includes: A set of files patterns which specify the files to include as resources under that specified directory, using * as a wildcard.
  • excludes: The same structure as includes, but specifies which files to ignore. In conflicts between include and exclude, exclude wins.
  • testResources: The testResources element block contains testResource elements. Their definitions are similar to resource elements, but are naturally used during test phases. The one difference is that the default (Super POM defined) test resource directory for a project is ${basedir}/src/test/resources. Test resources are not deployed.

Mybatis中自动注册的TypeHandler

register(Boolean.class, new BooleanTypeHandler());
register(boolean.class, new BooleanTypeHandler());
register(JdbcType.BOOLEAN, new BooleanTypeHandler());
register(JdbcType.BIT, new BooleanTypeHandler());
register(Byte.class, new ByteTypeHandler());
register(byte.class, new ByteTypeHandler());
register(JdbcType.TINYINT, new ByteTypeHandler());
register(Short.class, new ShortTypeHandler());
register(short.class, new ShortTypeHandler());
register(JdbcType.SMALLINT, new ShortTypeHandler());
register(Integer.class, new IntegerTypeHandler());
register(int.class, new IntegerTypeHandler());
register(JdbcType.INTEGER, new IntegerTypeHandler());
register(Long.class, new LongTypeHandler());
register(long.class, new LongTypeHandler());
register(Float.class, new FloatTypeHandler());
register(float.class, new FloatTypeHandler());
register(JdbcType.FLOAT, new FloatTypeHandler());
register(Double.class, new DoubleTypeHandler());
register(double.class, new DoubleTypeHandler());
register(JdbcType.DOUBLE, new DoubleTypeHandler());
register(Reader.class, new ClobReaderTypeHandler());
register(String.class, new StringTypeHandler());
register(String.class, JdbcType.CHAR, new StringTypeHandler());
register(String.class, JdbcType.CLOB, new ClobTypeHandler());
register(String.class, JdbcType.VARCHAR, new StringTypeHandler());
register(String.class, JdbcType.LONGVARCHAR, new ClobTypeHandler());
register(String.class, JdbcType.NVARCHAR, new NStringTypeHandler());
register(String.class, JdbcType.NCHAR, new NStringTypeHandler());
register(String.class, JdbcType.NCLOB, new NClobTypeHandler());
register(JdbcType.CHAR, new StringTypeHandler());
register(JdbcType.VARCHAR, new StringTypeHandler());
register(JdbcType.CLOB, new ClobTypeHandler());
register(JdbcType.LONGVARCHAR, new ClobTypeHandler());
register(JdbcType.NVARCHAR, new NStringTypeHandler());
register(JdbcType.NCHAR, new NStringTypeHandler());
register(JdbcType.NCLOB, new NClobTypeHandler());
register(Object.class, JdbcType.ARRAY, new ArrayTypeHandler());
register(JdbcType.ARRAY, new ArrayTypeHandler());
register(BigInteger.class, new BigIntegerTypeHandler());
register(JdbcType.BIGINT, new LongTypeHandler());
register(BigDecimal.class, new BigDecimalTypeHandler());
register(JdbcType.REAL, new BigDecimalTypeHandler());
register(JdbcType.DECIMAL, new BigDecimalTypeHandler());
register(JdbcType.NUMERIC, new BigDecimalTypeHandler());
register(InputStream.class, new BlobInputStreamTypeHandler());
register(Byte[].class, new ByteObjectArrayTypeHandler());
register(Byte[].class, JdbcType.BLOB, new BlobByteObjectArrayTypeHandler());
register(Byte[].class, JdbcType.LONGVARBINARY, new BlobByteObjectArrayTypeHandler());
register(byte[].class, new ByteArrayTypeHandler());
register(byte[].class, JdbcType.BLOB, new BlobTypeHandler());
register(byte[].class, JdbcType.LONGVARBINARY, new BlobTypeHandler());
register(JdbcType.LONGVARBINARY, new BlobTypeHandler());
register(JdbcType.BLOB, new BlobTypeHandler());
register(Object.class, UNKNOWN_TYPE_HANDLER);
register(Object.class, JdbcType.OTHER, UNKNOWN_TYPE_HANDLER);
register(JdbcType.OTHER, UNKNOWN_TYPE_HANDLER);
register(Date.class, new DateTypeHandler());
register(Date.class, JdbcType.DATE, new DateOnlyTypeHandler());
register(Date.class, JdbcType.TIME, new TimeOnlyTypeHandler());
register(JdbcType.TIMESTAMP, new DateTypeHandler());
register(JdbcType.DATE, new DateOnlyTypeHandler());
register(JdbcType.TIME, new TimeOnlyTypeHandler());
register(java.sql.Date.class, new SqlDateTypeHandler());
register(java.sql.Time.class, new SqlTimeTypeHandler());
register(java.sql.Timestamp.class, new SqlTimestampTypeHandler());

【转载】微服务架构下的分布式Session管理

大家好,很高兴在这里和大家进行微课堂的分享,今天进行分享的主题是《微服务架构下的分布式Session管理》。

主要大纲:

一、应用架构变迁下的Session管理

二、微服务架构下的Session管理

三、Session管理实践分享

一、应用架构变迁下的Session管理

Session一词直译为“会话”,意指有始有终的一系列动作/消息。Session是Web应用蓬勃发展的产物之一,在Web应用中隐含有“面向连接”和“状态保持”两个含义,同时也指代了Web服务器与客户端之间进行状态保持的解决方案。

在Web应用诞生之初,应用服务器与浏览器之间仅仅只是基于HTTP协议进行通信。而HTTP协议是无状态的,也就是说每一个请求之间都是相互独立的,互不关联。但是随着应用业务复杂化,服务器需要按照用户的一系列业务操作向用户提供某些特定的、按需的内容。这时候就需要通过保存用户状态,将用户的请求关联起来。Session管理正是这一问题的解决方案。

早期的Web应用基本都采用的是单体架构,也就是把一个使用了分层架构的Web应用部署在单节点Web服务器上的架构类型。在这种架构中,虽然采用了分层架构,将整个应用分为了表现层、业务逻辑层和数据访问层,每一层各司其职,让Web应用的各个方面都有所改善。但这样的分层只是停留于逻辑上。由于将所有代码部署在单个服务器节点上,随着应用不断迭代开发,单体应用将会发展成巨石型应用,臃肿不堪,难以维护。

在这样的单体架构中,由于所有的用户请求都是由这个唯一的服务器进行响应处理,所以只要把保存了用户信息和状态的Session对象,存放在应用服务器内存里,就能轻松地达到保持用户状态的目的。

随着Web应用的发展,用户访问量和业务复杂度与日俱增,应用的性能和代码的维护难度成为应用的瓶颈,为了突破瓶颈,开发者开始尝试在应用架构中引入负载均衡器,继而演化出了集群和分布式两种架构类型。

  • 集群,是指在多个服务器节点上部署相同的应用,例如上图中的服务器B和C,然后通过负载均衡器的分发功能,把用户请求分发到集群中的任意一个服务器节点上。如果有更大的访问量,只要向集群中增加服务器节点,就能改善压力。集群既能保证应用的高可用,又能提高应用的负载能力。
  • 分布式,是把原来的单体架构应用,通过分而治之的手段,按照业务功能,切分成一些小的模块应用,部署在不同服务器节点上,例如上图中的服务器A和B。然后通过负载均衡器和门户应用整合起来,组成一个完整的应用。

集群和分布式架构中,后端包含了多个服务器节点。当用户进行登录时,登录请求是由其中一个服务器节点进行响应,而后续的用户请求将可能被负载均衡器分发到其他服务器节点,这时候就可能因为这个服务器节点上没有用户Session,导致服务器判定用户是未登录状态,让用户重新登录。

所以,在集群和分布式架构中,必须保证用户进行登陆后,架构中的所有服务器节点都能共享Session数据。常用的Session管理方案有如下3种:

1、将Session对象保存在Cookie,然后存放在浏览器端。每次浏览器向服务器发送请求的时候,都会把整个Session对象放在请求里一起发送到服务器,以此来实现Session共享。这样的方案实现起来特别方便,但是由于Cookie的存储容量比较小,所以这个方案只适用于Session数据量小的场景。

2、Session复制。部分应用服务器能够支持Session复制功能,例如Tomcat。用户可以通过修改配置文件,让应用服务器进行Session复制,保持每一个服务节点的Session数据达到一致。但是这个方案的实现依赖于应用服务器。当应用被大量用户访问时,每个服务器都需要有一部分内存用来存放Session,同时因为大量Session通过网路传输进行复制,将会占用网络资源,还可能因为网络延迟导致程序异常。

3、Session粘滞。利用负载均衡器的分发能力,将同一浏览器上同一用户的请求,都定向发送到固定服务器上,让这个服务器处理该用户的所有请求,这样只要这个服务器上保存了用户Session,就能保证用户的状态一致性。但是这个方案依赖于负载均衡器,而且只适用于横向扩展的集群场景,不能满足分布式场景。

二、微服务架构下的Session管理

微服务架构是将一个应用拆分成一套小而相互关联的微服务,微服务之间通过暴露出来的API被其他微服务或系统所调用。在运行时 ,每个微服务实例通常是一个云虚拟机或者一个Docker。众多微服务综合起来,构成了一个完整的微服务架构应用。

微服务架构中的微服务一般可以分为两类:无状态服务和有状态服务。无状态服务比如应用服务器提供的公共服务,通常不保存数据,方便进行横向扩展。有状态服务则需要进行数据存储,例如数据库服务和缓存服务。在Web应用中,Session用来存储用户状态信息,所以Session管理也是有状态服务的一种。

微服务架构可以近似地看做是一个大型的分布式架构系统,但是与分布式架构相比,微服务架构让应用模块的划分更为精细,每个微应用大小合适,方便进行维护和管理。通过使用devops平台,可以让微服务模块的开发部署变得很敏捷

当应用由十几个甚至数十个部署在不同节点上的微服务组成时,如果还是沿用分布式架构中的Session管理方案,将会让Session管理的复杂度直线上升,同时很难保证整个架构中Session数据的一致性。

因此,在微服务架构下的Session管理,我们应该另辟蹊径,不再将Session对象保存在服务器的内存里,而是在应用架构中引入独立的中间存储介质,将整个应用架构中的Session对象进行统一管理。

个人认为,一个好的Session集中管理方案,应该具备以下4个特点:

  • 中间存储介质的读写速度要快。因为使用了Session集中管理后,将会在Session的读写操作中引入网络传输,与保存在服务器本地内存相比,读写速率会有所下降,所以必须保证中间存储介质的读写速度。
  • 中间存储介质要高可用。整个应用架构中的Session对象都将被保存在中间存储介质中,如果不能保证存储介质的高可用,整个应用都将变得不稳定。
  • Session管理方案要保证对用户的透明性,切换成集中管理后 ,对用户的使用应该是不会与影响的,用户使用的时候对方案改变无感知。
  • 管理方案不该和某一应用服务器耦合,应该适用于所有常规应用服务器。

从上述特点可以看出,Session集中管理的技术选型,应该从Session存储介质和管理方案实现两方面进行考虑。

三、Session管理实践分享

因为Session存储介质需要有较高的读写性能,所以应该选择缓存服务器作为存储介质。我们在进行微服务Session管理实践的时候,对目前业内常用的两种缓存服务器,Redis和Memcache,进行了对比,准备在两者之中选一个合适的缓存服务器来进行Session存储。

从表中的数据可能看出,虽然Redis的读写性能稍弱于Memcache,但是Redis支持的数据类型较多,而且支持数据的持久化。

此外,Memcache使用Slab Allocation机制进行内存管理,通过将内存分隔成特定长度块来解决内存碎片问题。同时Memcache采用最近最少使用(LRU)算法对slab进行内存回收。这就意味着,如果所有Session对象的大小大致相同,将会被Memcache存放在大小合适的slab中进行存储,一但这些slab被存满,再有新的数据进来,里面的存放的时间相对较早的Session对象就会被清除,导致用户变成未登录状态。

对比之后发现Redis更加适合用于Session存储。而且Redis3.0之后,提供了良好的主从复制和集群能力,能够很好地保证Session存储的高可用。Redis还提供了数据失效和订阅通知的能力,能为Session共享提供良好的支撑。

在Session集中管理方案的实现上,目前常用的方案有两种,一种是Memcache-Tomcat-Session,另一种是Spring Session。

Memcache-Tomcat-Session是一个基于Memcache和Tomcat实现Session集中管理的开源方案,通过修改Tomcat的server.xml文件,使用扩展的SessionManager替换Tomcat原有的Session管理器来实现集中管理。这个方案实现起来比较简单,但是与Tomcat耦合,不适用于其他应用服务器。

Spring Session是Spring提供的一套Session管理方案,通过一个SessionFilter将所有访问应用的请求都拦截下来,然后使用Request包装类接管Session管理。SpringSession不与应用服务器耦合,能适用于常规服务器。同时还提供了在浏览器下对同一应用存储多个Session等功能。

SpringSession优点颇多,所以开始的时候我们曾尝试将SpringSession集成到公司产品中来,进行Session集中管理,但在集成过程中考虑到以下几点,最终放弃了集成。

  • SpringSession功能丰富,但我们并不是都需要。
  • SpringSession的实现代码量较多,还需要配合Spring-data-redis进行使用。如果后续要对Session管理的代码进行修改维护,需要把SpringSession的代码都梳理一遍,学习维护成本比较高。

所以最终我们决定使用Redis作为Session的存储介质,然后参考SpringSession的实现理念,自己设计开发一套轻量级的Session集中管理实现。

同样使用SessionFilter进行用户请求拦截,然后通过Request包装类接管应用服务器的Session管理。在Request包装类中重写getSession方法。让用户在进行Session读写的时候去Redis中进行操作,而且使用Session的方法与过去一样,使得管理方案对用户透明。

在Session共享模块与Redis之间,基于jedis开发了一个分布式缓存SDK,用于进行通信,同时SDK可以提供扩展性,后续如果需要支持其他的缓存服务器,只要对SDK进行扩展开发即可。

然后为了保证Session集中管理方案的高可用,将会搭建Redis集群来存储Session对象。

这是一个推荐客户搭建的最小Redis集群,集群中共有4个Redis节点,两主两从。两个Master节点用来对Session数据进行分片存储,而Slaver节点用来对Matser进行数据备份和读写分离。

总结

maven filter和resource

1. 利用filter实现对资源文件(resouces)过滤


maven filter可利用指定的xxx.properties中对应的key=value对资源文件中的${key}进行替换,最终把你的资源文件中的username=${key}替换成username=val

       <!-- 过滤器,用于过滤resource中的各个文件 --> 
        <filters>
            <filter>src/main/resources/filtersTest.properties</filter>
        </filters>
        <resources>
            <resource>
                <directory>src/main/resources</directory>
                <!-- 是否使用过滤器 -->
                <filtering>true</filtering>
            </resource>
        </resources>

2. 利用profile来切换环境

<profiles>
    <profile>
        <id>dev</id>

        <!-- 默认激活开发配制,使用config-dev.properties来替换设置过虑的资源文件中的${key} -->
        <activation>
            <activeByDefault>true</activeByDefault>
        </activation>
        <build>
            <filters>
                <filter>config-dev.properties</filter>
            </filters>
        </build>
    </profile>
    <profile>
        <id>test</id>
        <build>
            <filters>
                <filter>config-dev.properties</filter>
            </filters>
        </build>
    </profile>
    <profile>
        <id>product</id>
        <build>
            <filters>
                <filter>config-product.properties</filter>
            </filters>
        </build>
    </profile>
</profiles>

3. 命令


maven clean install -Ptest — 激活id=”test”的profile

如何在android虚拟机上执行java jar文件

大家都知道,andriod apk大部分代码都是java代码,但是apk并不是运行在java虚拟机,而是运行在DVM上,而且编译好的java 代码也不能直接运行在DVM上。接下来就简单说下怎么运行jar在andriod手机上。

1.DVM & JVM

Dalvik虚拟机是Google等厂商合作开发的Android移动设备平台的核心组成部分之一。它可以支持已转换为.dex(即Dalvik Executable)格式的Java应用程序的运行,.dex格式是专为Dalvik设计的一种压缩格式,适合内存和处理器速度有限的系统.

Java虚拟机,大家可以google,很多详细的资料。

2.如何在andriod手机上运行jar

# 编辑java源文件
javac -cp src -d build src/Hello.java

# 在jvm上测试
java -cp build Hello

#通过dx工具把java class转化为dex文件
dx –dex –output=hello.jar Hello.class
cd ..

# 在andriod虚拟机上执行
dalvikvm -cp build/hello.jar Hello