本文将会不断总结更新
Spring中提供了FactoryBean接口,用于创建各种不同的Bean。
开发人员也可以自己实现该接口,常用于框架集成。比如mybatis-spring-1.1.0.jar包中的SqlSessionFactoryBean就是如此。
Spring针对JDBC,JMS,JPA等规范,都提供了相应的模板方法类,如JdbcTemplate,JmsTemplate, JpaTemplate。
例如JdbcTemplate,它提供了很多常用的增加,删除,查询,修改方法模板。而JMSTemplate则提供了对于消息的发送,接收方法等。下面是JMSTemplate的部分方法图:
Spring中AOP,事务等都大量运用了代理模式。
Spring中提供了一种事件监听机制,即ApplicationListener,可以实现Spring容器内的事件监听。可以参考这里
主要是以下两个接口:
发布消息
监听消息
Spring默认的创建Bean的作用域就是单例,即每个Spring容器中只存在一个该类的实例。可以通过@Scope(“prototype”)来修改成prototype模式,prototype在设计模式中叫做原型模式,实际上,Spring中对于@Scope(“prototype”)标记的Bean的处理的确是原型模式。
原型模式是创建型模式的一种,其特点在于通过“复制”一个已经存在的实例来返回新的实例,而不是新建实例。被复制的实例就是我们所称的“原型”,这个原型是可定制的。
原型模式多用于创建复杂的或者耗时的实例,因为这种情况下,复制一个已经存在的实例使程序运行更高效;或者创建值相等,只是命名不一样的同类数据。
Spring中,如果一个类被标记为”prototype”,每一次请求(将其注入到另一个bean中,或者以程序的方式调用容器的getBean()方法)都会产生一个新的bean实例。
但是,Spring不能对一个prototype Bean的整个生命周期负责,容器在初始化、配置、装饰或者
代码如下:
private static final Map<String, AtomicInteger> map = new HashMap<String, AtomicInteger>();
private static final Object locker = new Object();
public void increase(String key) {
AtomicInteger count = map.get(key);
if (count == null) {
synchronized (locker) {
if (map.get(key) == null) {
count = new AtomicInteger();
map.put(key, count);
}
}
}
count.incrementAndGet();
}
上面的代码会报空指针异常
正确代码应该如下:
private static final Map<String, AtomicInteger> map = new HashMap<String, AtomicInteger>();
private static final Object locker = new Object();
public void increase(String key) {
if (map.get(key) == null) {
synchronized (locker) {
if (map.get(key) == null) {
count = new AtomicInteger();
map.put(key, count);
简单工厂:
工厂方法:
抽象工厂:
简单工厂:适合创建同一级别的不同对象。
工厂方法:为每种产品提供一个工厂类,通过不同的工厂实例来创建不同的产品。工厂方法模式中我们把生成产品类的时间延迟,就是通过对应的工厂类来生成对应的产品类,在这里我们就可以实现“开发-封闭”原则,无论加多少产品类,我们都不用修改原来类中的代码,而是通过增加工厂类来实现。但是这还是有缺点的,如果产品类过多,我们就要生成很多的工厂类。
抽象工厂:针对产品族,比如每个汽车公司都要同时生产轿车,货车,客车,那么每一个工厂都要有对应的生产轿车,货车和客车的方法。所以,抽象工厂类中一般会有多个抽象方法。什么是产品族呢?简单的理解就是,不同牌子产的车里面会有跑车类型,家庭类型,商用类型等的车,不同牌子的车的跑车类型的车可以组成一个产品族。抽象工厂模式中我们可以定义实现不止一个接口,一个工厂也可以生成不止一个产品类,抽象工厂模式较好的实现了“开放-封闭”原则,是三个模式中较为抽象,并具一般性的模式。
下面当我们看一下,需要增加产品的时候,三种模式都需要如何操作。
简单工厂:如果是新增同一类型的产品(都是实现Product接口的),那么需要在工厂类的ifelse中新增一个判断。客户端不需要做变更
工厂方法:新增一个产品,我们就需要新增加一个工厂类。客户端也需要变更。
抽象工厂:新增一类产品,比如新增跑车,那么需要修改抽象工厂以及所有的实现类,改动很大。新增某一个产品,比如新增一款颜色的轿车,也需要单独的工厂实现类。
简单工厂 :用来生产同一等级结构中的任意产品。(对于增加新的产品,无能为力)
工厂方法 :用来生产同一等级结构中的固定产品。(支持增加任意产品)
抽象工厂 :用来生产不同产品族的全部产品。(对于增加新的产品,无能为力;支持增加产品族)
简单工厂在JDK中的应用有很多:
java.te
在Linux系统上,可以通过两种方式。
curl -fsSL https://get.docker.com/ | sh
curl如果没有安装,则需要先安装curl
这种方式安装成功之后,会自动启动docker
docker启动之后,可以通过docker run
命令来运行镜像。
docker run hello-world
运行举例:
root@mine:~# docker run hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
03f4658f8b78: Already exists
a3ed95caeb02: Already exists
Digest: sha256:8be990ef2aeb16dbcb9271ddfe2610fa6658d13f6dfb8bc72074cc1ca36966a7
Status: Downloaded newer image for hello-world:latest
Hello from Docker.
This message shows that your installation appears to be working correctly.
To generate this message, Docker took the following steps:
1. The Docker client contacted the Docker daemon.
2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
3. The Docker daemon created a new container from that image which runs
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class App
{
private static final Log log = LogFactory.getLog(App.class);
public static void main( String[] args ) {
log.info("rizhi ....");
}
}
可以看到,Log是通过LogFactory.getLog(Class clzz)方法获取的。
而getLog方法内部又是通过getFactory()方法,先获取到LogFactory,然后再创建Log的。
所以,commons-logging在选在使用哪个日志实现的时候,实际上是先选择使用哪个LogFactory。下面我们就来看一下这个过程(LogFactory类的public static LogFactory getFactory() throws LogConfigurationException方法)。
// Identify the class loader we will be using
ClassLoader contextClassLoader = getContextClassLoaderInternal();
if (contextClassLoader == null) {
// This is an odd enough situation to report about. This
// output will be a nuisance on JDK1.1, as the system
// classloader is null in that env
whereis java # 查找java文件
which java # 查看java命令执行路径
echo $JAVA_HOME #打印JAVA_HOME环境变量
echo $PATH
修改/etc/profile文件
vi 此文件/etc/profile
在profile文件末尾加入:
export JAVA_HOME=/usr/share/jdk1.6.0_20
export PATH=PATH
export CLASSPATH=.:JAVA_HOME/lib/tools.jar
注意:上面的/usr/share/jdk1.6.0_20是JDK安装路径,可以通过which java
查看。
修改完profile文件之后还没有生效,想要生效需要执行source profile
命令。
.bash_profile文件末尾加入:
export JAVA_HOME=/usr/share/jdk1.6.0_20
export PATH=PATH
export CLASSPATH=.:
在Windows中,如果我们在某个文件夹下,按住Shift同时点击鼠标右键,出现的菜单中有一项叫做“在此处打开命令行窗口”,如下图:
从这里打开命令行窗口之后,窗口中的路径就是当前目录下,这样就省去了切换目录的麻烦。
在Ubuntu中,默认没有该功能,如果要实现类似功能,需要安装一个软件:nautilus-open-terminal
sudo apt-get install nautilus-open-terminal
完成之后需要重启一下电脑,重启完成之后在任意目录下右键就有了。
PS:快速开启命令行 Ctrl+Alt+T,多个窗口通过Tab页的形式打开:Ctrl+Shift+T
在系统开发中,日志是很重要的一个环节,日志写得好对于我们开发调试,线上问题追踪等都有很大的帮助。但记日志并不是简单的输出信息,需要考虑很多问题,比如日志输出的速度,日志输出对于系统内存,CPU的影响等,为此,出现了很多日志框架,以帮助开发者解决这些问题。
比较常用的有Log4j,SLF4j,Commons-logging,logback。当然,JDK本身也提供了java.util.logging包来提供对日志的支持。
Commons-loggin:是apache最早提供的日志的门面接口。它的主要作用是提供一个日志门面,使用者可以使用不同的日志实现。用户可以自由选择第三方的日志组件作为具体实现,像log4j,或者jdk自带的logging, common-logging会通过动态查找的机制,在程序运行时自动找出真正使用的日志库。common-logging内部有一个Simple logger的简单实现,但是功能很弱。
SLF4j:是Simple Logging Facade for Java的简称,即java的简单日志门面。类似于Apache Common-Logging,是对不同日志框架提供的一个门面封装,可以在部署的时候不修改任何配置即可接入一种日志实现方案。但是,他在编译时静态绑定真正的Log库。使用SLF4J时,如果你需要使用某一种日志实现,那么你必须选择正确的SLF4J的jar包的集合(各种桥接包)。
Log4j:经典的一种日志解决方案。内部把日志系统抽象封装成Logger 、appender 、pattern等实现。我们可以通过配置文件轻松的实现日志系统的管理和多样化配置。pache的一个开放源代码项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件、甚至是套接口服务器、NT的事件记录器、UNIXSyslog守护进程等;用户也可以控制每一条日志的输出格式;通过定义每一条日志信息的级别,用户能够更加细致地控制日志的生成过程。这些可以通过一个 配置文件来灵活地进行配置,而不需要修改程序代码。
logback:也是一种日志实现。Logback是由log4j创始人设
Base64是一种数据表示方法,它使用64个可打印字符来表示二进制数据,所以才叫做Base64。
Base64一般用于处理文本数据,表示、传输、存储。比如MIME中的email,以及在xml中存储复杂数据。
编码
将普通数据转换成符合Base64标准的数据的过程。
解码
将Base64标准的数据转换成普通数据的过程。
52个字母:大写字母+小写字母
10个数字:0~9
两个特殊字符:+ 和 /
以上就够64个了,但是有时候还会用一个“=”,等号的作用是填充,后面会讲到。
Base64字符对照表:
数值 | 字符 | 数值 | 字符 | 数值 | 字符 | 数值 | 字符 |
---|---|---|---|---|---|---|---|
0 | A | 16 | Q | 32 | g | 48 | w |
1 | B | 17 | R | 33 | h | 49 | x |
2 | C | 18 | S | 34 | i | 50 | y |
3 | D | 19 | T | 35 | j | 51 | z |
4 | E | 20 | U | 36 | k | 52 | 0 |
5 | F | 21 | V | 37 | l | 53 | 1 |
6 | G | 22 | W | 38 | m | 54 | 2 |
7 | H | 23 | X | 39 | n | 55 | 3 |
8 | I | 24 | Y | 40 | o | 56 | 4 |
9 | J | 25 | Z | 41 | p | 57 | 5 |
10 | K | 26 | a | 42 | q | 58 | 6 |
11 | L | 27 | b | 43 | r | 59 | 7 |
12 | M | 28 | c | 44 | s | 60 | 8 |
13 | N | 29 | d | 45 | t | 61 | 9 |
14 | O | 30 | e | 46 | u | 62 | + |
15 | P | 31 |