了解bean的一生

容器启动之后,并不会马上就根据bean的定义去实例化相应的bean。容器在在实例化bean之前,已经拥有了所有bean相关的BeanDefinition。一旦通过BeanFactory的getBean()方法请求获取某个对象实例的时候,才有可能触发bean实例化阶段的活动。

  • bean的实例化与BeanWrapper
  1. 容器在内部实现的时候,采用策略模式来决定采用何种方式初始化bean实例。通常,可以通过反射或者CGLIB动态字节码来初始化相应的bean实例获取动态生成其子类。容器只要根据相应bean定义的BeanDefinition取得实例化信息,结合CglibSubclassingInstantiationStrategy以及不同的bean定义类型,就可以返回实例化完成的对象实例。但是,并不是返回直接构造完成的对象实例,而是以BeanWrapper对构造完成的对象实例进行包裹,返回相应的BeanWrapper实例。

  2. BeanWrapper在spring框架内部使用,BeanWrapper会将对其包裹的bean设置或者获取相应的属性值。

扩展spring容器

springIoc容器它会以某种方式加载ConfigMetadata(通常就是XML格式的配置信息或是注解),然后根据信息绑定整个系统的对象,最终组装成一个可用的基于轻量级容器的应用系统。spring的IOC容器实现以上功能的过程,基本上可以按照类似的流程分为两个阶段,即容器启动阶段和Bean实例化阶段。spring的IOC容器在实现的时候,充分运用了这个两个实现阶段的不同特点,在每个阶段加入了相应的容器扩展点,以便我们可以根据具体场景的需要加入自定义的扩展逻辑。

  • spring提供了一种叫做BeanFactoryPostProcessor的容器扩展机制,该机制允许我们在容器实例化相应对象之前,对注册到容器的BeanDefinition所保存的信息做相应的修改。这就相当于在容器实现的第一阶段最后加入一道工序,让我们对最终的BeanDefinition做一些额外的操作,比如修改其中bean定义的某些属性,为bean等一增加其它信息等
  • PropertyPlaceholderConfigurer允许我们在XML配置文件中使用占位符(PlaceHolder),并将这些占位符所代表的资源单独配置到简单的properties文件中来加载。这些都是很常见的:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="clone">
    <!-- 基本属性driverClassName、 url、user、password -->
    <property name="driverClassName" value="${jdbc.driverClassName}" />
    <property name="url" value="${account.jdbc.url}" />
    <property name="username" value="${account.jdbc.username}" />
    <property name="password" value="${account.jdbc.password}" />

    <!-- 配置初始化大小、最小、最大 -->
    <!-- 通常来说,只需要修改initialSize、minIdle、maxActive -->
    <!-- 初始化时建立物理连接的个数,缺省值为0 -->
    <property name="initialSize" value="2" />
    <!-- 最小连接池数量 -->
    <property name="minIdle" value="2" />
    <!-- 最大连接池数量,缺省值为8 -->
    <property name="maxActive" value="10" />

    </bean>
1
2
3
4
jdbc.url=jdbc\:mysql\://192.168.4.201\:3306/test?useUnicode\=true&characterEncoding\=utf-8&allowMultiQueries\=true
jdbc.username=root
jdbc.password=123456
jdbc.driverClassName=com.mysql.jdbc.Driver

基本机制:当BeanFactory在第一阶段加载完成所有配置信息时,BeanFactory中保存的对象的属性信息还只是以占位符的形式存在,如${jdbc.url}。当PropertyPlaceholderConfigurer被作为BeanFactoryPostProcessor应用时,它会使用properties配置文件中的配置信息来替换相应BeanDefinition中占位符表示的属性值。

HTTP协议

客户端连上web服务器后,若想获得web服务器中的某个web资源,需遵守一定的通讯格式,Http协议用于定义客户端与web服务器通讯的格式。HTTP是hypertext transfer protocol(超文本传输协议)的简写,它是TCP/IP协议的一个应用层协议,用于定义WEB浏览器与WEB服务器之间交换数据的格式。

HTTP请求

  • 客户端连上服务器后,向服务器请求某个web资源,称之为客户端向服务器发送了一个HTTP请求,一个完整的HTTP请求包括:一个请求行、若干请求头、实体内容。请求行用于描述客户端的请求方式、请求资源的名称以及使用的HTTP协议版本号。请求头用于描述客户端请求哪台主机以及一些客户端的一些环境信息。例如:
1
2
3
4
5
6
7
8
9
10
11
GET / HTTP/1.1
Host: localhost:8080
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Encoding: gzip, deflate, sdch
Accept-Language: zh-CN,zh;q=0.8,en;q=0.6
Cookie: JSESSIONID=8B8D0E6D210BBD1AD3A1CD058AEF9738

  • 请求行中的GET称之为请求方式,请求方式有:POST、GET、HEAD、OPTIONS、DELETE、TRACE、PUT,常用的是GET和POST。这两种方式的区别是,如果请求方式为GET,可以在URL地址后以?的形式带上给服务器的数据,多个数据之间以&进行分隔。GET方式的特点,在URL地址后附带的参数是有限制的,其数据容量通常不能超过1k。如果请求方式为POST,则可以在请求的实体内容中向服务器发送数据,传送的数据量无限制。

  • HTTP请求中的常用头

    1. Accept: 客户机支持的数据类型
    2. Accept-Charset:客户机采用的编码
    3. Accept-Encoding:客户机支持的数据压缩格式
    4. Accept-Language:客户机的语言环境
    5. Host:要访问的主机名
    6. If-Modified-Since:资源的缓存时间
    7. Referer:从哪个资源来访问服务器的(可用于防盗链)
    8. User-Agent:客户机的软件环境
    9. Cookie:向服务器发送的特定数据
    10. Connection:是否要与服务器保持连接

工厂方法模式

工厂方法模式是类的创建模式,又叫做虚拟构造子模式(Virtual Constructor)模式或多态性工厂(Polymorphic Factory)模式。工厂方法模式的用意是定义一个创建产品对象的工厂接口,将实际创建工作推迟到子类中。

  1. 简单工厂模式的缺点

    在简单工厂模式中,一个工厂类处于对产品类实例化的中心位置上,它知道每一个产品并决定哪一个产品类应当被实例化,这个模式的优点是允许客户端相对独立于产品创建的过程。但这个模式的缺点是对“开-闭”原则的支持不够,因为如果有新的产品加入到系统中去,就需要修改工厂类,将必要的逻辑加入到工厂类中。

  2. 工厂方法模式的引进

    工厂方法模式是简单工厂模式的进一步抽象和推广,由于使用了多态性,工厂方法模式保持了简单工厂模式的优点,而且克服了他的缺点。首先,在工厂方法模式中,核心的工厂类不再负责所有的产品的创建,而是将具体创建的工作交给子类去做。这个核心类摇身一变,成为了一个抽象工厂角色。仅负责给出具体工厂子类必须实现的接口,而不解除哪一个产品类应当被实例化这种细节。这种进一步抽象化得结果,使这种工厂方法模式可以用来允许系统在不修改具体工厂角色的情况下引进新的产品,这一特点无疑使得工厂模式具有超过简单工厂模式的优越性。

  3. 工厂方法模式的结构

    • 抽象工厂(Creator)角色:担任这个角色的是工厂方法模式的核心,它是与应用程序无关的。任何在模式中创建对象的工厂类必须实现这个接口或抽象类。
    • 具体工厂(Concreate Creator)角色:担任这个角色的是实现了抽象工厂接口的具体java类。具体工厂角色含有与应用密切相关的逻辑。并且受到应用程序的调用以创建产品对象。
    • 抽象产品(Product)角色:工厂方法模式所创建的对象的超类型,也就是产品对象的共同父类或共同拥有的接口或抽象类。
    • 具体产品(Concrete Product)角色:这个角色实现了抽象产品角色所声明的接口(抽象类)。工厂方法模式所创建的每一个对象都是这个具体产品角色的实例。
  1. 实例
  • 抽象工厂角色
1
2
3
4
5
public interface Creator {

public abstract Product factory();

}
  • 抽象产品角色
1
2
3
public interface Product {

}
  • 具体工厂角色
1
2
3
4
5
6
7
8
9
10
11
12
13
public class ConcreteCreator1 implements Creator {

public Product factory() {
return new ConcreteProduct1();
}
}

public class ConcreteCreator2 implements Creator {

public Product factory() {
return new ConcreteProduct2();
}
}
  • 具体产品角色
1
2
3
4
5
6
7
8
9
10
11
public class ConcreteProduct1 implements Product {
public ConcreteProduct1 {
//so something
}
}

public class ConcreteProduct2 implements Product {
public ConcreteProduct2 {
//so something
}
}
  • 客户端角色Client类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class Client {

private static Creator creator1;
private static Creator creator2;

private static Product prod1;
private static Product prod2;

public static void main(String[] args) {
creator1 = new ConcreteCreator1();
prod1 = creator1.factory();

creator2 = new ConcreteCreator2();
prod2 = creator2.factory();
}
}

简单工厂模式

工厂模式专门将大量有共同接口的类实例化。工厂模式可以动态决定将哪一个类实例化,不必事先知道每次要实例化哪个类。工厂模式有以下几种形态:

  • 简单工厂模式(Simple Factory):又称静态工厂模式(Static Factory Method Pattern)

  • 工厂方法模式(Factory Method): 又称多态性工厂模式或虚拟构造子模式

  • 抽象工厂模式(Abstract Factory): 又称工具箱模式(Kit或ToolKit)

简单工厂模式

简单工厂模式,或称静态工厂方法模式,是不同的工厂方法的一个特殊实现。

简单工厂模式,或称静态工厂方法模式,是不同的工厂方法的一个特殊实现。比如有一个农场公司,专门向市场销售各类水果,我们会真么描述这个系统:

  • 定义一个各种水果都适用的接口
1
2
3
4
5
6
7
8
9
10
11
12
public interface Fruit {

//生长
void grow();

//收获
void harvest();

//种植
void plant();

}
  • 苹果类(多年生植物,多出一个treeAge性质)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public class Apple implements Fruit {

private int treeAge;

public int setTreeAge(int treeAge) {
this.treeAge = treeAge;
}

public int getTreeAge() {
return this.treeAge;
}

/*
* 生长
*/

public void grow() {
System.out.println("Apple is growing...");
}

/*
* 种植
*/

public void harvest() {
System.out.println("Apple is harvest.");
}

/*
* 收获
*/

public void plant() {
System.out.println("Apple has ben planted.");
}
}
  • 葡萄类,分有籽和无籽
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public class Grape implements Fruit {

private boolean seedless;

public int setSeedless(boolean seedless) {
this.seedless = seedless;
}

public int getTreeAge() {
return this.seedless;
}

/*
* 生长
*/

public void grow() {
System.out.println("Grape is growing...");
}

/*
* 种植
*/

public void harvest() {
System.out.println("Grape is harvest.");
}

/*
* 收获
*/

public void plant() {
System.out.println("Grape has ben planted.");
}
}
  • 农场园丁类根据客户端的要求,创建不同的水果对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class FruitGardener {

/**
* 静态工厂方法
*/

public static Fruit factory(String which) {

switch(name) {
case "apple":
return new Apple();
break;
case "grape":
return new Grape();
break;
default:
return null;
break;
}
}
}
  • 客户端调用代码
1
2
FruitGardener.factory("apple");
FruitGardener.factory("grape");

总结:简单工厂模式涉及到工厂角色、抽象产品角色以及具体产品角色3个角色

  • 工厂类(Creator)角色:担任这个角色的是工厂方法模式的核心,含有与应用紧密相关的逻辑。工厂类在客户端的直接调用下创建产品对象,它往往由一个具体java类实现。
  • 抽象产品(Product)角色:担任这个角色的类是由工厂方法模式所创建的对象的父类,或它们有共同的接口。抽象产品角色可以由用一个java接口或java抽象类实现。
  • 具体产品(Concrete Product)角色:工厂方法模式所创建的任何对象都是这个角色的实例,具体产品角色由一个具体Java类实现。

ArrayList源码解析

ArrayList 实现了 List 接口,意味着可以插入空值,也可以插入重复的值,非同步 ,它是基于数组 的一个实现。本文分析基于jdk1.7~

先看其变量部分,对ArrayList的操作本质上是对其底层对象数组的更改。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24



//默认初始化数组大小

private static final int DEFAULT_CAPACITY = 10;



//空数组

private static final Object[] EMPTY_ELEMENTDATA = {};



//存放数组的地方

transient Object[] elementData; // non-private to simplify nested class access



//数组长度

private int size;
  1. add方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86

public boolean add(E e) {

//数组扩容

ensureCapacityInternal(size + 1); // Increments modCount!!

//数组原长度+1的索引位置存放新添加的元素

elementData[size++] = e;

return true;

}





private void ensureCapacityInternal(int minCapacity) {

if (elementData == EMPTY_ELEMENTDATA) {

minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);

}



ensureExplicitCapacity(minCapacity);

}



private void ensureExplicitCapacity(int minCapacity) {

modCount++;



// overflow-conscious code

if (minCapacity - elementData.length > 0)

grow(minCapacity);

}



private void grow(int minCapacity) {

// overflow-conscious code

int oldCapacity = elementData.length;

//数组扩容:10 15 22 33.....每次扩容其长度增加1.5倍

int newCapacity = oldCapacity + (oldCapacity >> 1);

if (newCapacity - minCapacity < 0)

newCapacity = minCapacity;

if (newCapacity - MAX_ARRAY_SIZE > 0)

newCapacity = hugeCapacity(minCapacity);

// minCapacity is usually close to size, so this is a win:

elementData = Arrays.copyOf(elementData, newCapacity);

}



private static int hugeCapacity(int minCapacity) {

if (minCapacity < 0) // overflow

throw new OutOfMemoryError();

return (minCapacity > MAX_ARRAY_SIZE) ?Integer.MAX_VALUE :MAX_ARRAY_SIZE;

}

java对象初始化过程

对象初始化过程

1
2
3
4
5
6
7
8
9
class Person() {
private String name;
private int age;

Person(String name, int age) {
this.name =name;
this.age = age;
}
}

上面是一个简单的java类。创建一个对象:

1
Person p = new Person("zhangsan", 20);

这句创建对象的过程做了哪些事?

  • 因为new使用到了Person.class,所以会先找到Person.class文件并加载
  • 执行该类中的static代码块(如果有),给Person.class类进行初始化
  • 在堆内存中开辟空间,分配内存地址
  • 在堆内存中建立对象特有属性(例子中的name和age),并进行默认初始化
  • 对属性进行显示初始化
  • 对对象进行构造代码块初始化
  • 对对象进行对应的构造函数初始化
  • 将内存地址赋给栈内存中的p变量

Centos下重置mysql密码

1.停止mysql服务

1
service mysqld stop

2.使用安全模式启动mysql

1
mysqld_safe --skip-grant-tables &

3.使用root用户登陆mysql

1
mysql -u root

4.重置密码

1
2
3
4
>use mysql;
>update user set password=PASSWORD("mynewpassword") where User='root';
>flush privileges;
>quit

5.停止mysql

1
service mysqld stop

6.重启mysql

1
service mysqld start

7.使用新密码登陆mysql

1
mysql -u root -p

Just do it!

servlet初步

Servlet是sun公司提供的一门用于开发动态web资源的技术,一个Servlet就是运行在web容器中的小型java程序,接收和响应一个客户端的http请求。

Sun公司在其API中提供了一个Servlet接口

为了实现该接口,你可以写一个类继承javax.servlet.GenericServlet或是javax.servlet.http.HttpServlet,这两个类实现了Servlet接口定义的一些方法。
用户若想用发一个动态web资源(即开发一个Java程序向浏览器输出数据),需要完成以下2个步骤:

  • 编写一个Java类,实现servlet接口

  • 把开发好的Java类部署到web服务器中

详解Servlet接口

该接口定义了初始化Servlet的方法、响应请求、从一个web容器卸载Servlet,这实质是一个对象的生命周期。

  • Servlet对象创建,会调用init方法来进行初始化

  • 客户端请求会使用service方法来响应

  • 该servlet停止服务,会使用destroy方法销毁,然后jvm进行垃圾回收

  • 除了生命周期方法,此接口提供getServletConfig方法,该方法可以附加一些启动信息来启动servlet。getServletInfo方法,它允许servlet返回有关自身的基本信息,例如作者,版本和 版权