小建儿的小站


  • 首页

  • 关于

  • 标签

  • 分类

  • 搜索

设计模式-状态模式

发表于 2018-08-18 | 分类于 设计模式 |
字数统计: | 阅读时长 ≈

状态模式

  很多情况下,一个对象的行为取决于一个或多个状态变化的属性,这样的属性叫状态。这样的对象叫做有状态的对象,这样的状态是从事先定义好的一系列值中获取的。当一个这样的对象与外部产生互动时,其内部状态就会改变,从而使得系统的行为也随之发生改变。

示例

环境类

1
2
3
4
5
6
7
8
9
10
11
12

public class Context {
private State state;

public State getState() {
return state;
}

public void setState(State state) {
this.state = state;
}
}

抽象状态接口

1
2
3
4
5
6

public interface State {

void handle(Context context);

}

具体状态类

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

public class StartState implements State {
@Override
public void handle(Context context) {
System.out.println("player is in start state");
context.setState(this);
}

@Override
public String toString() {
return "start state";
}
}

public class StopState implements State {
@Override
public void handle(Context context) {
System.out.println("player is in stop state");
context.setState(this);
}

@Override
public String toString() {
return "stop state";
}
}

测试类

1
2
3
4
5
6
7
8
9
10
11
public void test() {
Context context = new Context();

StartState startState = new StartState();
startState.handle(context);

StopState stopState = new StopState();
stopState.handle(context);


}

结果

1
2
3

player is in start state
player is in stop state

总结

  状态模式和命令模式一样,可以用于消除if-else等条件选择语句。

  • 优点

  封装了状态转换规则,状态转换代码可以封装在环境类或者具体状态类中,可以对状态转换代码进行集中管理,而不是分散在一个个业务代码中。

  将所有与状态有关的行为放到一个类中,只需要注入不同的状态对象即可是环境对象拥有不同的行为。

  允许状态转换逻辑与状态对象合成一体,而不是提供一个巨大的条件语句块,状态模式可以让我们避免使用庞大的条件语句来讲业务方法和状态转换代码交织在一起。

  • 缺点

  增加系统内类的个数。
  实现复杂,增加系统设计难度
  对“开闭原则”支持不好,增加新的状态类需要修改负责状态转换的代码。

设计模式-命令模式

发表于 2018-08-18 | 分类于 设计模式 |
字数统计: | 阅读时长 ≈

命令模式

  在软件设计中,我们经常需要向某些对象发送请求,但是并不知道请求的接收者是谁,也不知道被请求的操作是哪个。我们只需在程序运行时指定具体的请求接收者即可,此时可以使用命令模式来进行设计,使得请求发送者和接受者之间消除耦合,让对象的调用关系更加灵活。

  命令模式可以对发送者和接受者完全解耦,发送者和接受者之间没有直接引用关系,发送请求的对象只需要知道如何发送请求,而不必知道如何完成请求。这就是命令模式的动机。

例子

命令的执行者

1
2
3
4
5
6
7
8
9
10
11

public class Light {

public void on() {
System.out.println("灯打开了");
}

public void off() {
System.out.println("灯关了");
}
}

抽象命令接口

1
2
3
4
5
6
7

public interface Command {


void execute();

}

具体命令实现类

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

public class LightOffCommand implements Command {

private Light light;

public LightOffCommand(Light light) {
this.light = light;
}

@Override
public void execute() {
light.off();
}
}


public class LightOnCommand implements Command {

private Light light;

public LightOnCommand(Light light) {
this.light = light;
}

@Override
public void execute() {
light.on();
}
}

调用者类

这里假设为遥控器

1
2
3
4
5
6
7
8
9
10
11
12
13
14

public class Controller {

private Command command;

public void setCommand(Command command) {
this.command = command;
}

public void buttonOnPressed() {
command.execute();
}

}

测试类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
    public void test() {
Controller controller = new Controller();
Light light = new Light();
LightOffCommand lightOffCommand = new LightOffCommand(light);
LightOnCommand lightOnCommand = new LightOnCommand(light);

controller.setCommand(lightOffCommand);
controller.buttonOnPressed();
controller.setCommand(lightOnCommand);
controller.buttonOnPressed();
}


/**
灯关了
灯打开了
**/

总结

命令模式的好处在于可以将命令的请求这和命令的执行者进行解耦,但是在复杂场景下,命令类会变得很多,不方便进行管理。

storm系列1:storm集群搭建

发表于 2018-08-16 | 分类于 storm |
字数统计: | 阅读时长 ≈

  最近在研究流式特征处理,所以搭建了storm集群环境,把过程发出来,以备后续查看。

安装包准备

  • jdk: oracle官网下载的jdk1.8.0_181版本

  • zookeeper: zookeeper下载的zookeeper-3.4.12版本

  • storm: storm下载的apache-storm-1.2.2版本

配置环境变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14

PATH=$PATH:$HOME/.local/bin:$HOME/bin
JAVA_HOME=/home/user/jdk1.8.0_181
JRE_HOME=$JAVA_HOME/jre
STORM_HOME=/home/user/apache-storm-1.2.2
CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ZOOKEEPER_HOME=/home/user/zookeeper-3.4.12
PATH=$PATH:$JAVA_HOME/bin:$STORM_HOME/bin:$ZOOKEEPER_HOME/bin
export PATH
export JAVA_HOME
export JRE_HOME
export CLASSPATH
export ZOOKEEPER_HOME
export STORM_HOME

配置zookeeper

修改配置文件

  zookeeper需要修改ZOOKEEPER_HOME/conf/zoo.cfg文件,加入下列信息

1
2
3
4
5
6
7
8
9

tickTime=2000
dataDir=/var/zookeeper/
clientPort=2181
initLimit=5
syncLimit=2
server.1=m7-pce-hdp01:2888:3888
server.2=m7-pce-hdp02:2888:3888
server.3=m7-pce-hdp03:2888:3888

其中dataDir是zookeeper的数据文件目录;server.id=host:port:port,其中id是每个节点的编号,这个编号需要在dataDir目录下创建myid文件中写入,m7-pce-hdp01~m7-pce-hdp03是hostname,第一个port用于连接leader的端口,第二个port用于连接leader的选举端口。

启动zookeeper

执行ZOOKEEPER_HOME/bin/zkServer.sh启动zookeeper,并执行zkServer.sh status,查看是否启动成功

配置storm

  storm配置文件在STORM_HOME/conf/storm.yaml,需要配置一下几个信息

配置zookeeper列表

1
2
3
4
5

storm.zookeeper.servers:
- "m7-pce-hdp01"
- "m7-pce-hdp02"
- "m7-pce-hdp03"

配置nimbus

1
2

nimbus.seeds: ["m7-pce-hdp01"]

配置storm本地dir

1
2

storm.local.dir: "/home/user/apache-storm-1.2.2/workdir"

配置supervisor.slots.ports

supervisor.slots.ports是指每个机器可以启动多少个worker,一个端口号代表一个worker

1
2
3
4
5
6

supervisor.slots.ports:
- 6700
- 6701
- 6702
- 6703

启动Storm集群

启动nimbus集群

1
2

nohup storm nimbus &

  用jps查看后台线程会发现多了nimbus(先显示config value,配置正确后变成nimbus)

启动supervisor

1
2

nohup storm supervisor &

  用jps查看后台线程出现Supervisor

启动监控ui

1
2

nohup storm ui &

  用jps查看后台线程出现core

在浏览器中输入“http://m7-pce-hdp01:8080/index.html”即可看到

提交任务

  集群配置完,我们开始向集群提交任务。

配置本地storm

  需要在storm.yaml文件中配置nimbus

1
2

nimbus.host: "m7-pce-hdp01"

准备程序

  在STORM_HOME/examples下有很多示例代码,我们选用storm-starter进行测试。这里需要用maven进行打包,执行mvn package就行。然后我们就能在target文件夹下找到storm-starter-1.2.2.jar,一会就提交它。

提交任务

1
2

storm jar storm-starter-1.2.2.jar storm/starter/StatefulTopology wordcountexample

然后输入storm list

1
2
3
4
5

2703 [main] INFO o.a.s.u.NimbusClient - Found leader nimbus : m7-pce-hdp01:6627
Topology_name Status Num_tasks Num_workers Uptime_secs
-------------------------------------------------------------------
wordcountexample ACTIVE 7 1 183702

也可以进入ui页面进行查看运行状态。storm任务运行完也不会停止,需要手动kill。

总结

  以上就是storm集群的搭建过程,很简单,基本上没遇到什么问题。

设计模式-代理模式

发表于 2018-08-13 | 分类于 设计模式 |
字数统计: | 阅读时长 ≈

代理模式

  代理模式是属于结构模式之一。该模式的作用主要是为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个客户不想或者不能直接使用另一个对象,此时代理对象可以在客户端和目标对象之间起到中介的作用。

  代理模式的实现方式有静态代理、jdk动态代理和cglib动态代理。

静态代理

  静态代理是指在程序运行前代理类的.class文件就已经存在,是由程序员在编码时手动实现的。

  示例如下:

定义一个接口

1
2
3
4
5
public interface Person {

void speak();

}

实现类

1
2
3
4
5
6
7
8

public class Actor implements Person {

@Override
public void speak() {
System.out.println("这是actor");
}
}

代理类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

public class Agent implements Person {

private Actor actor;

public Agent(Actor actor) {
this.actor = actor;
}

@Override
public void speak() {
System.out.println("进入代理");
actor.speak();
System.out.println("退出代理");
}
}

测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14

public class StaticProxyTest {
public static void main(String[] args) {
Actor actor = new Actor();
Agent agent = new Agent(actor);
agent.speak();
}
}

/**
进入代理
这是actor
退出代理
**/

jdk动态代理

  jdk动态代理与静态代理最大的区别就是代理类的.class文件是在运行时生成的,而且被代理类必须要实现一个接口。

  示例如下,接口和被代理类和静态代理一样

代理类

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

public class JdkProxy implements InvocationHandler {

private Actor actor;

public JdkProxy(Actor actor) {
this.actor = actor;
}

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("进入代理");
method.invoke(actor, args);
System.out.println("退出代理");
return null;
}

public Object getProxy() {
return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), this.actor.getClass().getInterfaces(), this);
}
}

测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

public static void main(String[] args) {
Actor actor = new Actor();
JdkProxy jdkProxy = new JdkProxy(actor);
Person proxy = (Person) jdkProxy.getProxy();
proxy.speak();
}

/**

进入代理
这是actor
退出代理

**/

cglib动态代理

  cglib是一个功能强大的代码生成包,其底层依赖asm框架。cglib实现动态代理最大的特点就是被代理类不需要实现接口。

  示例如下

被代理类

1
2
3
4
5
6
7
public class ActorNoInterface {

public void speak() {
System.out.println("我是actor没有实现接口");
}

}

代理类

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

public class CglibProxy implements MethodInterceptor {

private Object actor;

public CglibProxy(ActorNoInterface actor) {
this.actor = actor;
}

@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("进入cglib代理");
methodProxy.invokeSuper(o, objects);
System.out.println("退出cglib代理");
return null;
}

public Object getInstance() {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(this.actor.getClass());
enhancer.setCallback(this);
return enhancer.create();
}
}

测试

1
2
3
4
5
6
7
8

public class CglibProxyTest {
public static void main(String[] args) {
CglibProxy cglibProxy = new CglibProxy(new ActorNoInterface());
ActorNoInterface actor = (ActorNoInterface) cglibProxy.getInstance();
actor.speak();
}
}

spring-ioc

发表于 2018-08-06 | 分类于 java |
字数统计: | 阅读时长 ≈

sprint ioc容器

  在spring中,最基本的IOC容器接口就是BeanFactory,这个接口为具体的IOC容器实现提供了基本功能的规定。

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

public interface BeanFactory {

//这里是对FactoryBean的转义定义,因为如果使用bean的名字检索FactoryBean得到的对象是工厂生成的对象,
//如果需要得到工厂本身,需要转义
String FACTORY_BEAN_PREFIX = "&";


//这里根据bean的名字,在IOC容器中得到bean实例,这个IOC容器就是一个大的抽象工厂。
Object getBean(String name) throws BeansException;

//这里根据bean的名字和Class类型来得到bean实例,和上面的方法不同在于它会抛出异常:如果根据名字取得的bean实例的Class类型和需要的不同的话。
Object getBean(String name, Class requiredType) throws BeansException;

//这里提供对bean的检索,看看是否在IOC容器有这个名字的bean
boolean containsBean(String name);

//这里根据bean名字得到bean实例,并同时判断这个bean是不是单例
boolean isSingleton(String name) throws NoSuchBeanDefinitionException;

//这里对得到bean实例的Class类型
Class getType(String name) throws NoSuchBeanDefinitionException;

//这里得到bean的别名,如果根据别名检索,那么其原名也会被检索出来
String[] getAliases(String name);

}

  BeanFactory里只对IOC容器的基本行为做了定义,对bean的如何定义及其加载过程并不关心。就像我们只关心我们得到什么产品的对象,至于工厂是怎么产生这些对象的,这个接口并不关心。

Spring IOC初始化过程

  spring ioc初始化顺序主要是:读取xml资源、解析xml资源、注册到BeanFactory。完成初始化过程后,bean就在BeanFactory中等待调用。下面以ClassPathXmlApplicationContext入口类为例,详细说明初始化过程。

从传入配置到创建BeanFactory

首先入口处在ClassPathXmlApplicationContext类中

1
2
3
4
5
6
7
8
9
10
11

public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
throws BeansException {

super(parent);
setConfigLocations(configLocations);
if (refresh) {
//就是从这里开始进行初始化
refresh();
}
}

refresh方法在父类AbstractApplicationContext中,它具体的实现是这样的

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

public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
//准备工作,记录容器启动的时间、标记启动状态
prepareRefresh();

//这步完成创建BeanFactory、加载bean、注册bean的过程
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

//设置BeanFactory的类加载器
prepareBeanFactory(beanFactory);

try {
postProcessBeanFactory(beanFactory);

invokeBeanFactoryPostProcessors(beanFactory);

registerBeanPostProcessors(beanFactory);

initMessageSource();

initApplicationEventMulticaster();

onRefresh();

registerListeners();

//这里完成所有singleton bean的初始化
finishBeanFactoryInitialization(beanFactory);
//广播时间,applicationContext初始化完成
finishRefresh();
}

catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}

destroyBeans();

cancelRefresh(ex);

throw ex;
}

finally {
resetCommonCaches();
}
}
}

接下来去obtainFreshBeanFactory方法中看看进行了什么操作

1
2
3
4
5
6
7
8
9
10

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
//主要逻辑,完成创建BeanFactory及Bean的加载和注册
refreshBeanFactory();
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (logger.isDebugEnabled()) {
logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
}
return beanFactory;
}

然后再去AbstractRefreshableApplicationContext类中看看refreshBeanFactory方法做了哪些操作

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

@Override
protected final void refreshBeanFactory() throws BeansException {
//如果已经加载过BeanFactory,那么销毁所有bean,并关闭BeanFactory
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
//这里创建了一个BeanFactory,createBeanFactory就是返回一个DefaultListableBeanFactory实例
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
//设置是否允许覆盖,是否允许循环引用
customizeBeanFactory(beanFactory);
//这里把bean加载到BeanFactory中,后面具体分析
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}

bean的加载及注册

loadBeanDefinitions方法在AbstractRefreshableApplicationContext中是个抽象方法,其实现在子类AbstractXmlApplicationContext类中

1
2
3
4
5
6
7
8
9
10
11
12
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
//创建一个XmlBeanDefinitionReader
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

beanDefinitionReader.setEnvironment(this.getEnvironment());
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
//初始化该reader,主要是给子类覆盖用
initBeanDefinitionReader(beanDefinitionReader);
//这里会加载bean
loadBeanDefinitions(beanDefinitionReader);
}

loadBeanDefinitions方法主体在XmlBeanDefinitionReader中

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

public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
Assert.notNull(encodedResource, "EncodedResource must not be null");
if (logger.isInfoEnabled()) {
logger.info("Loading XML bean definitions from " + encodedResource.getResource());
}

Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
if (currentResources == null) {
currentResources = new HashSet<EncodedResource>(4);
this.resourcesCurrentlyBeingLoaded.set(currentResources);
}
if (!currentResources.add(encodedResource)) {
throw new BeanDefinitionStoreException(
"Detected cyclic loading of " + encodedResource + " - check your import definitions!");
}
try {
InputStream inputStream = encodedResource.getResource().getInputStream();
try {
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
//核心部分
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
}
finally {
inputStream.close();
}
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(
"IOException parsing XML document from " + encodedResource.getResource(), ex);
}
finally {
currentResources.remove(encodedResource);
if (currentResources.isEmpty()) {
this.resourcesCurrentlyBeingLoaded.remove();
}
}
}

其中DefaultBeanDefinitionDocumentReader类承担了大部分xml标签解析的功能,解析的细节就不具体展开了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
//delegate.parseBeanDefinitionElement方法会去解析各个节点,最后生成BeanDefinition,由于bean有name和alias属性,所以这里定义了BeanDefinitionHolder来存储BeanDefinition
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
//这里完成注册
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to register bean definition with name '" +
bdHolder.getBeanName() + "'", ele, ex);
}
// Send registration event.
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}

registerBeanDefinition方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

public static void registerBeanDefinition(
BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
throws BeanDefinitionStoreException {

String beanName = definitionHolder.getBeanName();
//注册
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
//有别名的话,根据别名注册一遍
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
//这里没有存alias->beanDefinition,而是存储beanName->alias
for (String alias : aliases) {
registry.registerAlias(beanName, alias);
}
}
}

registerBeanDefinition方法主体位于DefaultListableBeanFactory中

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

public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {

Assert.hasText(beanName, "Bean name must not be empty");
Assert.notNull(beanDefinition, "BeanDefinition must not be null");

if (beanDefinition instanceof AbstractBeanDefinition) {
try {
((AbstractBeanDefinition) beanDefinition).validate();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Validation of bean definition failed", ex);
}
}

BeanDefinition oldBeanDefinition;

oldBeanDefinition = this.beanDefinitionMap.get(beanName);
if (oldBeanDefinition != null) {
//若不允许覆盖,则报错
if (!isAllowBeanDefinitionOverriding()) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
"': There is already [" + oldBeanDefinition + "] bound.");
}
//用框架定义的bean还是用于定义的bean
else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {
// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
if (this.logger.isWarnEnabled()) {
this.logger.warn("Overriding user-defined bean definition for bean '" + beanName +
"' with a framework-generated bean definition: replacing [" +
oldBeanDefinition + "] with [" + beanDefinition + "]");
}
}
//用新bean覆盖旧bean
else if (!beanDefinition.equals(oldBeanDefinition)) {
if (this.logger.isInfoEnabled()) {
this.logger.info("Overriding bean definition for bean '" + beanName +
"' with a different definition: replacing [" + oldBeanDefinition +
"] with [" + beanDefinition + "]");
}
}
else {
if (this.logger.isDebugEnabled()) {
this.logger.debug("Overriding bean definition for bean '" + beanName +
"' with an equivalent definition: replacing [" + oldBeanDefinition +
"] with [" + beanDefinition + "]");
}
}
this.beanDefinitionMap.put(beanName, beanDefinition);
}
else {
//判断是否有其他Bean开始初始化
if (hasBeanCreationStarted()) {
// Cannot modify startup-time collection elements anymore (for stable iteration)
synchronized (this.beanDefinitionMap) {
this.beanDefinitionMap.put(beanName, beanDefinition);
List<String> updatedDefinitions = new ArrayList<String>(this.beanDefinitionNames.size() + 1);
updatedDefinitions.addAll(this.beanDefinitionNames);
updatedDefinitions.add(beanName);
this.beanDefinitionNames = updatedDefinitions;
if (this.manualSingletonNames.contains(beanName)) {
Set<String> updatedSingletons = new LinkedHashSet<String>(this.manualSingletonNames);
updatedSingletons.remove(beanName);
this.manualSingletonNames = updatedSingletons;
}
}
}
else {
//最正常的是进入到这里,注册过程就是把beanName和beanDefinition放入map中
this.beanDefinitionMap.put(beanName, beanDefinition);
this.beanDefinitionNames.add(beanName);
this.manualSingletonNames.remove(beanName);
}
this.frozenBeanDefinitionNames = null;
}

if (oldBeanDefinition != null || containsSingleton(beanName)) {
resetBeanDefinition(beanName);
}
}

截止到这里,已经初始化了Bean容器,配置也转化成了BeanDefinition,并注册在了BeanFactory。

初始化singleton bean

  在上面提到的refersh方法中,有一个finishBeanFactoryInitialization方法,完成初始化所有单例的bean

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

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
//初始化名为conversionService的Bean
if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
beanFactory.setConversionService(
beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
}

//初始化LoadTimeWeaverAware类型的Bean,一般用于织入第三方模块,在class文件加载JVM的时候动态织入
String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
for (String weaverAwareName : weaverAwareNames) {
getBean(weaverAwareName);
}

beanFactory.setTempClassLoader(null);

beanFactory.freezeConfiguration();
//这里初始化其他bean
beanFactory.preInstantiateSingletons();
}

继续到DefaultListableBeanFactory类中看看preInstantiateSingletons方法

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

public void preInstantiateSingletons() throws BeansException {
if (this.logger.isDebugEnabled()) {
this.logger.debug("Pre-instantiating singletons in " + this);
}

List<String> beanNames = new ArrayList<String>(this.beanDefinitionNames);
//触发所有non-lazy的singleton bean的初始化操作
for (String beanName : beanNames) {
//合并父bean中的配置,即<bean parent="">
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
//非抽象、非懒加载、单例
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
//判断是不是FactoryBean,是的话在beanName前加上&符号
if (isFactoryBean(beanName)) {
final FactoryBean<?> factory = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName);
boolean isEagerInit;
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
@Override
public Boolean run() {
return ((SmartFactoryBean<?>) factory).isEagerInit();
}
}, getAccessControlContext());
}
else {
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean<?>) factory).isEagerInit());
}
if (isEagerInit) {
//普通bean初始化的地方
getBean(beanName);
}
}
else {
getBean(beanName);
}
}
}

// Trigger post-initialization callback for all applicable beans...
for (String beanName : beanNames) {
Object singletonInstance = getSingleton(beanName);
if (singletonInstance instanceof SmartInitializingSingleton) {
final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
if (System.getSecurityManager() != null) {
AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
smartSingleton.afterSingletonsInstantiated();
return null;
}
}, getAccessControlContext());
}
else {
smartSingleton.afterSingletonsInstantiated();
}
}
}
}

getBean(String name)方法完成普通bean的初始化,该方法是从BeanFactory中获取bean的方法,但是初始化过程也封装在这个方法中

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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
@Override
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}

//getBean是用来从容器中获取bean的,这里先看有没有初始化,没有的话先初始化,完成初始化直接返回
protected <T> T doGetBean(
final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
throws BeansException {
//获取beanname,如果是factoryBean前面加个&
final String beanName = transformedBeanName(name);
//返回值
Object bean;
//检查是否已经创建过了
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
if (logger.isDebugEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
}
else {
logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
}
}
//如果是普通bean返回sharedInstance,如果是factoryBean返回它创建的那个实例对象
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}

else {
// Fail if we're already creating this bean instance:
// We're assumably within a circular reference.
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
//检查beanDefinition是否存在
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
//如果不存在,看看父容器中是否存在
String nameToLookup = originalBeanName(name);
if (args != null) {
// Delegation to parent with explicit args.
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
else {
// No args -> delegate to standard getBean method.
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
}

if (!typeCheckOnly) {
markBeanAsCreated(beanName);
}
//这里要开始创建bean了,对于singleton bean来说,容器中没有创建过该bean
//对于prototype的bean来说,本身就要创建一个新bean
try {
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
//先初始化所有依赖的bean
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dependsOnBean : dependsOn) {
if (isDependent(beanName, dependsOnBean)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dependsOnBean + "'");
}
//注册依赖关系
registerDependentBean(dependsOnBean, beanName);
//初始化被依赖的bean
getBean(dependsOnBean);
}
}
//创建singleton实例
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
try {
//这里是主要逻辑!!
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
destroySingleton(beanName);
throw ex;
}
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
//如果是prototype的
else if (mbd.isPrototype()) {
// It's a prototype -> create a new instance.
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}

else {
String scopeName = mbd.getScope();
final Scope scope = this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
}
try {
Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
}
});
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
throw new BeanCreationException(beanName,
"Scope '" + scopeName + "' is not active for the current thread; consider " +
"defining a scoped proxy for this bean if you intend to refer to it from a singleton",
ex);
}
}
}
catch (BeansException ex) {
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
}
//检查类型对不对,对的话就返回了
if (requiredType != null && bean != null && !requiredType.isAssignableFrom(bean.getClass())) {
try {
return getTypeConverter().convertIfNecessary(bean, requiredType);
}
catch (TypeMismatchException ex) {
if (logger.isDebugEnabled()) {
logger.debug("Failed to convert bean '" + name + "' to required type [" +
ClassUtils.getQualifiedName(requiredType) + "]", ex);
}
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
}
return (T) bean;
}

接下来是创建bean,我们来到了AbstractAutowrieCapableBeanFactory类,这个类和Autowire注解有关

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

protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException {
if (logger.isDebugEnabled()) {
logger.debug("Creating instance of bean '" + beanName + "'");
}
RootBeanDefinition mbdToUse = mbd;
//确保BeanDefinition中的class被加载
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
mbdToUse = new RootBeanDefinition(mbd);
mbdToUse.setBeanClass(resolvedClass);
}

// Prepare method overrides.
try {
mbdToUse.prepareMethodOverrides();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
beanName, "Validation of method overrides failed", ex);
}

try {
// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
}
catch (Throwable ex) {
throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
"BeanPostProcessor before instantiation of bean failed", ex);
}
//这里创建bean
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
if (logger.isDebugEnabled()) {
logger.debug("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
}

继续看doCreateBean方法

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
87
88
89
90
91
92
93
94

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) {
// Instantiate the bean.
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
//这里完成实例化
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
//这个就是bean实例
final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
Class<?> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);

synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
mbd.postProcessed = true;
}
}

// Eagerly cache singletons to be able to resolve circular references
// even when triggered by lifecycle interfaces like BeanFactoryAware.
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isDebugEnabled()) {
logger.debug("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
addSingletonFactory(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
return getEarlyBeanReference(beanName, mbd, bean);
}
});
}

Object exposedObject = bean;
try {
//这里负责装配属性
populateBean(beanName, mbd, instanceWrapper);
if (exposedObject != null) {
//处理bean初始化完之后的回调
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
}
catch (Throwable ex) {
if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
throw (BeanCreationException) ex;
}
else {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
}
}

if (earlySingletonExposure) {
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet<String>(dependentBeans.length);
for (String dependentBean : dependentBeans) {
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
if (!actualDependentBeans.isEmpty()) {
throw new BeanCurrentlyInCreationException(beanName,
"Bean with name '" + beanName + "' has been injected into other beans [" +
StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
"] in its raw version as part of a circular reference, but has eventually been " +
"wrapped. This means that said other beans do not use the final version of the " +
"bean. This is often the result of over-eager type matching - consider using " +
"'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
}
}
}
}

// Register bean as disposable.
try {
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}

return exposedObject;
}

到这里为止,完成了整个初始化流程。上面的过程里,最重要的三个函数是创建bean实例的方法createBeanInstance,一个是依赖注入的populateBean方法,还有回调方法initializeBean。

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

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {
//确保加载了class
Class<?> beanClass = resolveBeanClass(mbd, beanName);
//校验访问权限
if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
}

if (mbd.getFactoryMethodName() != null) {
//采用工厂方法实例化
return instantiateUsingFactoryMethod(beanName, mbd, args);
}
//如果不是第一次创建,我们可以通过第一次创建知道采用无参构造函数还是构造函数依赖注入来完成实例化
boolean resolved = false;
boolean autowireNecessary = false;
if (args == null) {
synchronized (mbd.constructorArgumentLock) {
if (mbd.resolvedConstructorOrFactoryMethod != null) {
resolved = true;
autowireNecessary = mbd.constructorArgumentsResolved;
}
}
}
if (resolved) {
if (autowireNecessary) {
return autowireConstructor(beanName, mbd, null, null);
}
else {
return instantiateBean(beanName, mbd);
}
}

//判断用有参构造函数
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
if (ctors != null ||
mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||
mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
//构造函数依赖注入
return autowireConstructor(beanName, mbd, ctors, args);
}
//调用无参构造函数
return instantiateBean(beanName, mbd);
}

进入无参构造函数方法看看

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

protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) {
try {
Object beanInstance;
final BeanFactory parent = this;
if (System.getSecurityManager() != null) {
beanInstance = AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
return getInstantiationStrategy().instantiate(mbd, beanName, parent);
}
}, getAccessControlContext());
}
else {
//实例化
beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);
}
BeanWrapper bw = new BeanWrapperImpl(beanInstance);
initBeanWrapper(bw);
return bw;
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);
}
}
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

@Override
public Object instantiate(RootBeanDefinition bd, String beanName, BeanFactory owner) {
//如果不存在方法覆盖,那就是用java反射进行实例化,否则使用CGLIB
if (bd.getMethodOverrides().isEmpty()) {
Constructor<?> constructorToUse;
synchronized (bd.constructorArgumentLock) {
constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod;
if (constructorToUse == null) {
final Class<?> clazz = bd.getBeanClass();
if (clazz.isInterface()) {
throw new BeanInstantiationException(clazz, "Specified class is an interface");
}
try {
if (System.getSecurityManager() != null) {
constructorToUse = AccessController.doPrivileged(new PrivilegedExceptionAction<Constructor<?>>() {
@Override
public Constructor<?> run() throws Exception {
return clazz.getDeclaredConstructor((Class[]) null);
}
});
}
else {
constructorToUse = clazz.getDeclaredConstructor((Class[]) null);
}
bd.resolvedConstructorOrFactoryMethod = constructorToUse;
}
catch (Exception ex) {
throw new BeanInstantiationException(clazz, "No default constructor found", ex);
}
}
}
//构造方法实例化
return BeanUtils.instantiateClass(constructorToUse);
}
else {
// Must generate CGLIB subclass.
return instantiateWithMethodInjection(bd, beanName, owner);
}
}

属性注入

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

protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {
//bean实例的所有属性
PropertyValues pvs = mbd.getPropertyValues();

if (bw == null) {
if (!pvs.isEmpty()) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
}
else {
// Skip property population phase for null instance.
return;
}
}

//到这步bean实例化完成,但是还没开始属性设值
boolean continueWithPropertyPopulation = true;

if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
continueWithPropertyPopulation = false;
break;
}
}
}
}

if (!continueWithPropertyPopulation) {
return;
}

if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||
mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);

// Add property values based on autowire by name if applicable.
if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
//通过名字找到属性
autowireByName(beanName, mbd, bw, newPvs);
}

// Add property values based on autowire by type if applicable.
if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
//通过类型进行装配
autowireByType(beanName, mbd, bw, newPvs);
}

pvs = newPvs;
}

boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE);

if (hasInstAwareBpps || needsDepCheck) {
PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
if (hasInstAwareBpps) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvs == null) {
return;
}
}
}
}
if (needsDepCheck) {
checkDependencies(beanName, mbd, filteredPds, pvs);
}
}

//设置实例的属性值
applyPropertyValues(beanName, mbd, bw, pvs);
}

处理回调

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

protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
invokeAwareMethods(beanName, bean);
return null;
}
}, getAccessControlContext());
}
else {
invokeAwareMethods(beanName, bean);
}

Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}

try {
//处理bean定义中的init-method
//或者bean实现了InitializingBean接口,调用afterPropertiesSet方法
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}

if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}

设计模式-工厂模式

发表于 2018-08-06 | 分类于 设计模式 |
字数统计: | 阅读时长 ≈

工厂模式

  工厂模式是常见的5中创建型设计模式之一,主要用于新建对象场景。首先我们要明确为什么要使用工厂模式,在程序中new一个对象然后使用是最基本的需求,但是如果该对象发生一些改变或者派生出新对象,势必需要修改原代码,这样做破坏了开放封闭原则。所以我们希望又一个专门的类来产生我们要用的对象,使用时直接跟它请求需要的对象就好了,这样即使对象产生过程发生变化使用对象的类也不需要进行修改。其实可以认为new一个类是一种硬编码。这个时候工厂模式就能帮我们解决这个问题。工厂模式又细分为简单工厂、工厂方法和抽象工厂,下面我们来详细解释三种模式的结构。

举例分析

  话说有一位土豪想有一辆车,最直接的办法就是自己造,Benz奔驰、Bmw宝马、Audi奥迪,自己动手丰衣足食。但是自己造太麻烦还累,土豪有钱,费那个劲干啥,可以直接去工厂买啊。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

public abstract class Car {
...
}


public class Audi extends Car{
...
}


public class Bmw extends Car {
...
}

public class Benz extends Car{
...
}

  于是土豪来到了三个工厂考察。

简单工厂

  土豪来到了第一家小工厂,他想要的Benz、BMW、Audi都有,土豪很满意。我们看这个工厂是怎么生产汽车的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class CarFactory{

public static Car getCar(String type) throws Exception{
if(type.equals("Benz")){
return new Benz();
}else if(type.equals("Audi")){
return new Audi();
}else if(type.equals("Bmw")){
return new Bmw();
}else{
throw new Exception();
}
}

}

  土豪转念一想,这仨车太low,老子要布加迪,你能生产么。工厂领导傻眼了,他们工厂只能生产这三种车,要想生产其他的还要升级生产线。土豪一听,那我还是看看其他的工厂吧。

  简单工厂实现方式很简单,但是一但产品类型增加该方法又面临着修改,产品类型较多的时候逻辑复杂度会增加,不利于系统维护,依然不符合开闭原则。

工厂方法

  于是土豪来到了第二家工厂,这家工厂很大,总工厂下面有小工厂,生产线也是标准化的,能根据土豪的需要增加生产线,布加迪不是梦,土豪很满意。

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

public interface class Factory{
Car createCar();
}

public class AudiFactory implements Factory{

public Car createCar(){
return new Audi();
}
}
public class BenzFactory implements Factory{

public Car createCar(){
return new Benz();
}
}
public class BmwFactory implements Factory{

public Car createCar(){
return new Benz();
}
}

  土豪很满意,但是又想了想平时需要开一辆商务车,撩妹子需要一辆跑车,让这个工厂单开一条生产线生产跑车再提车妹子都跑了,于是摇摇头继续考察第三家工厂。
  使用时创建一个具体的工厂,然后调用createCar方法即可。这种实现方式的缺点是没增加一种新车型,需要新建一个对应的factory类。

抽象工厂

  土豪来到了第三家工厂,这家工厂把车按品牌分类,每个品牌包括商务车和跑车,于是它旗下的商务车工厂专门生产各种品牌的商务车,跑车工厂专门生产各个品牌的跑车。

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

public interface AudioCar{
...
}

public interface BWMCar{
...
}

public class AudioBusinessCar implements AudioCar{
...
}

public class AudioSportCar implements AudioCar{
...
}

public class BMWBusinessCar implements BMWCar{
...
}

public class BMWSportCar implements BMWCar{
...
}


public interface CarFactory{
AudioCar createAudioCar();
BMWCar createBMWCar();
}

public class BusinessCarFactory implements CarFactory{
public AudioCar createAudioCar(){
return new AudioBudinessCar();
}

public BMWCar createBMWCar(){
return new BMWBudinessCar();
}
}

public class SportCarFactory implements CarFactory{
public AudioCar createAudioCar(){
return new AudioSportCar();
}

public BMWCar createBMWCar(){
return new BMWSportCar();
}
}

  土豪一看很满意,直接提了两辆车回家。

  这种方式比较适合新增产品族,比如工厂扩大生产想生产轿车,直接增加一个轿车工厂就好了。但是如果新增产品,比如增加Benz车的跑车和商务车,那基本需要对所有类进行修改。

总结

  • 抽象工厂和工厂方法模式最大的区别在于工厂方法针对的是一个产品等级结构,而抽象工厂需要面对多个产品等级结构。
  • 当抽象工厂中只存在一个产品等级结构,抽象工厂退化成工厂方法模式
  • 当工厂方法模式中抽象工厂与具体工厂合并,提供一个统一的工厂来创建对象,并将创建对象的方法设置为静态方法时,工厂方法退化成简单工厂模式。

设计模式-如何防止单例模式被破坏

发表于 2018-07-26 | 分类于 设计模式 |
字数统计: | 阅读时长 ≈

单例模式是否安全

  在设计模式-单例模式这篇博客介绍了单例模式的几种实现方式,但是按照上述方式是否能够保证一定是单例呢?答案是否定的,如果不加限制,通过反射和序列化可以破坏单例模式。

破坏单例模式

反射

  单例模式把类的构造方法设置为private访问级别,导致外部类无法新建对象,通过反射我们可以修改访问级别,从外部新建单例类对象。以饿汉模式为例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class StarveSingleton {

private static StarveSingleton instance = new StarveSingleton();

private StarveSingleton(){}

public static StarveSingleton getInstance() {
return instance;
}


public static void main(String[] args) {
//输出true
System.out.println(StarveSingleton.getInstance() == StarveSingleton.getInstance());
Class clazz = StarveSingleton.class;
Constructor constructor= clazz.getDeclaredConstructor(null);
constructor.setAccessible(true);
StarveSingleton instance = (StarveSingleton) constructor.newInstance(null);
//输出false
System.out.println(instance == StarveSingleton.getInstance());
}
}

  从结果来看,通过反射的方式,单例模式被破坏,我们可以随意产生新的单例类实例。

序列化

  如果单例类继承了serializable接口,那么序列化也可以破坏单例模式。依然以饿汉模式为例

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

public class StarveSingleton implements Serializable{

private static StarveSingleton instance = new StarveSingleton();

private StarveSingleton(){}

public static StarveSingleton getInstance() {
return instance;
}

public static void main(String[] args) throws IOException, ClassNotFoundException {

ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream);
StarveSingleton starveSingleton = StarveSingleton.getInstance();
objectOutputStream.writeObject(starveSingleton);

byte[] bytes = outputStream.toByteArray();

ObjectInputStream inputStream = new ObjectInputStream(new ByteArrayInputStream(bytes));
StarveSingleton instance = (StarveSingleton) inputStream.readObject();
//输出false
System.out.println(starveSingleton == instance);

}
}

  可以看出序列化可以破坏单例模式。

如何防止单例模式被破坏

反射

  可以在构造函数里配置一个标志位,当构造函数被第二次调用时报错

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

public class StarveSingleton implements Serializable {
//设置flag
private static boolean flag = false;

private static StarveSingleton instance = new StarveSingleton();

private StarveSingleton() {
synchronized (StarveSingleton.class) {
//第一次调用的时候更改该变量的值,第二次再调用会报错
if (!flag) {
flag = !flag;
} else {
throw new RuntimeException("单例模式被破坏");
}
}
}

public static StarveSingleton getInstance() {
return instance;
}


public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {

System.out.println(StarveSingleton.getInstance() == StarveSingleton.getInstance());
Class<StarveSingleton> clazz = StarveSingleton.class;
Constructor<StarveSingleton> constructor = clazz.getDeclaredConstructor(null);
constructor.setAccessible(true);
StarveSingleton instance = constructor.newInstance();
System.out.println(instance == StarveSingleton.getInstance());

}
}

  这样就解决了反射破坏单例的问题。

序列化

  对于序列化来说,需要实现readSolve()方法来保证每次返回的都是一个实例

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

public class StarveSingleton implements Serializable {

private static StarveSingleton instance = new StarveSingleton();

private StarveSingleton() {

}

public static StarveSingleton getInstance() {
return instance;
}


public Object readResolve() {
return instance;
}

public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {

ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream);
StarveSingleton starveSingleton = StarveSingleton.getInstance();
objectOutputStream.writeObject(starveSingleton);

byte[] bytes = outputStream.toByteArray();

ObjectInputStream inputStream = new ObjectInputStream(new ByteArrayInputStream(bytes));
StarveSingleton instance = (StarveSingleton) inputStream.readObject();
System.out.println(starveSingleton == instance);
}
}

  readResolve方法是ObjectInputStream类进行反序列化的一个特殊机制,这里后续再展开,总之这里实现该方法可以保证单例不被破坏。

总结

  下面是我对这个知识点的心得。如何破坏单例模式,这道题怎么思考呢?单例模式和创建对象相关,我们知道创建对象有4种方式

  1. 直接new
  2. 调用clone方法
  3. 序列化反序列化
  4. 反射

其中方式1已经被单例模式限制住,方式2我们一般很少实现clone接口,所以可以破坏单例模式的方法就从3,4而来。

设计模式-单例模式

发表于 2018-07-19 | 分类于 设计模式 |
字数统计: | 阅读时长 ≈

单例模式

  单例模式是比较常用的设计模式之一,单例对象的类必须保证全局只有一个实例存在。其实现方式有很多种,本篇博客主要介绍常见的几种实现方式。

  单例模式最基本的原则:保证该类构造方法的访问权限为private。

饿汉模式

  饿汉模式是指类初始化的时候先创建好该类实例,获取实例的时候总是返回该实例。

1
2
3
4
5
6
7
8
9
10
11
12

public class StarveSingleton {

//先产生实例
private static StarveSingleton instance = new StarveSingleton();
//保证构造函数私有化,这样无法从外部初始化该类
private StarveSingleton(){}
//提供获取实例方法
public static StarveSingleton getInstance() {
return instance;
}
}

懒汉模式

  懒汉模式可以延迟类的初始化,即类加载阶段不进行初始化操作,只在第一次使用单例类的时候进行初始化,主要用于一些类初始化开销比较大的情况。
  缺点:多线程情况下需要特殊处理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class LazySingleton {

//初始化是该引用为null
private static LazySingleton instance = null;
//私有化构造方法
private LazySingleton() {

}
//获取类实例方法
public static LazySingleton getInstance() {
//第一次调用getInstance方法时,完成初始化
if (instance == null) {
instance = new LazySingleton();
}
return instance;
}


}

静态内部类

  饿汉模式不能实现延迟加载,占用内存;懒汉模式需要进行线程安全控制,并且影响性能。这时候静态内部类模式提供了另一种比较好的方式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

public class StaticSingleton {

//私有化构造方法
private StaticSingleton() {

}
//静态内部类
private static class SingletonHolder {
private static final StaticSingleton STATIC_SINGLETON = new StaticSingleton();
}
//获取类实例方法
public static StaticSingleton getInstance() {
return SingletonHolder.STATIC_SINGLETON;
}

}

  由于外部类的初始化并不会引发静态内部类SingletonHolder的初始化,所以只有在第一次调用getInstance方法时才会触发静态内部类的初始化,从而完成实例化工程。

枚举类

  枚举类是目前比较推荐的实现单例的方案,因为枚举类实现简单,并且可以保证线程安全和序列化的安全。

1
2
3
4
5
6

public enum EnumSingleton {

Instance;

}

双检锁

  前面提到过懒汉模式可能会遇到线程安全问题,双检索实现方式可以保证线程安全和延迟初始化。但是该模式只能保证在1.5版本之后的jvm上运行的效果。

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

public class DoubleCheckSignelton {
//引用设置为空,并且用volatile修饰
private static volatile DoubleCheckSignelton instance = null;
//私有化构造方法
private DoubleCheckSignelton() {

}
//提供获取实例方法
public static DoubleCheckSignelton getInstance() {
//第一次判断引用是否为空
if (instance == null) {
//防止多条线程同时实例化该类,所以加锁
synchronized (DoubleCheckSingleton.class) {
//此时有可能其他线程已经完成了实例化,所以再进行一次非空检测,确认是否需要进行类的实例化
if (instance == null) {
//确认没有进行过实例化,new一个新实例
instance = new DoubleCheckSignelton();
}
}
}
return instance;
}


}

相比枚举实现方式,双检索复杂一些。其中instance必须要用volatile修饰,此处的volatile并不是为了保证可见性,而是为了禁止重排序。产生新实例的时候一般按照开辟内存空间-创建实例-引用指向实例内存地址,但是重排序可能会将这个顺序改为开辟内存空间-引用指向实例内存地址-创建实例,如果一个线程按照第二种顺序进行操作,最后创建实例出现了问题,没有完成创建对象的工作,下一个线程进行非空检测时发现引用已经指向了新的实例地址,认为初始化工作已完成,直接返回了该引用,但实际上无法使用该实例。所以需要volatile保证类的初始化顺序。

总结

  以上就是常见的实现单例模式的方法,但是上述模式并不能完全保证全局只有一个实例,下一篇我们将深入地讲解哪些操作可以破坏单例模式,以及如何防止这些情况的发生。

java多线程-Unsafe

发表于 2018-07-13 | 分类于 java |
字数统计: | 阅读时长 ≈

Unsafe类解析

Unsafe类简介

  Unsafe类位于sun.misc包下,Unsafe类可以直接操作内存,并提供了无锁并发的实现方式CAS(compare and swap),juc包下的大部分工具都是基于该类实现,所以要想深入理解juc必须先要了解Unsafe。然而Java官方并不建议使用该类,所以我们无法在程序进行调用,需要通过反射机制进行调用。

Unsafe类使用

  查看源码,会发现该类的构造方法是private的,这意味这我们无法通过直接创建该类的示例。但是其内部有这样一个类变量,并且提供了访问方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
	
private static final Unsafe theUnsafe;

....

private Unsafe() {
}

@CallerSensitive
public static Unsafe getUnsafe() {
Class var0 = Reflection.getCallerClass();
if (!VM.isSystemDomainLoader(var0.getClassLoader())) {
throw new SecurityException("Unsafe");
} else {
return theUnsafe;
}
}
....

我们先尝试直接调用getUnsafe方法

1
2
3
4
5
6
7
8
9

public void testUnsafe() {

Unsafe.getUnsafe();

}

Exception in thread "main" java.lang.SecurityException: Unsafe
at sun.misc.Unsafe.getUnsafe(Unsafe.java:90)

结果发现程序报错,java不允许我们直接调用该类,所以这时候需要采用特殊手段,即通过反射方式获取theUsafe类变量。

1
2
3
4
5
6
7
8

public void testUnsafe() throws NoSuchFieldException, IllegalAccessException {

Field field = Unsafe.class.getDeclaredField("theUnsafe");
field.setAccessible(true);
Unsafe unsafe = (Unsafe) field.get(null);

}

常用方法

CAS

  该类最重要的方法就是CAS相关方法,通过这些方法可以实现无锁并发。

  锁可以按照策略分为乐观锁和悲观锁,悲观锁认为每次访问共享资源都会发生冲突,所以需要对每一次数据访问加锁。而乐观锁认为共享资源的访问不会总是发生冲突,没有冲突的时候线程继续执行,一旦发生冲突,通过CAS技术保证线程安全。

  CAS的核心思想是维护三个值,即待更新变量、预期值、新值,如果待更新变量的值等于预期值,则将其更新为新值,否则说明该值已经被其他线程修改,此时不执行更新操作。

  Unsafe中,比较常用的cas方法有

1
2
3
4
5
6
//var1是待更新对象,var2是对象内存的偏移量,通过偏移量获取该字段的值,var4是预期值,var5是要设置的值
public final native boolean compareAndSwapObject(Object var1, long var2, Object var4, Object var5);

public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);

public final native boolean compareAndSwapLong(Object var1, long var2, long var4, long var6);

  1.8中还新增了下面几个方法

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
//给定对象和字段偏移量,将其增加var4,这里需要注意,是先get再add,返回值是get的值,不返回add后的值
public final int getAndAddInt(Object var1, long var2, int var4) {
int var5;
do {
var5 = this.getIntVolatile(var1, var2);
} while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));
return var5;
}

//同上,只不过把类型变成long
public final long getAndAddLong(Object var1, long var2, long var4) {
long var6;
do {
var6 = this.getLongVolatile(var1, var2);
} while(!this.compareAndSwapLong(var1, var2, var6, var6 + var4));

return var6;
}

//给定对象和字段偏移量,将其设置为var4,这里需要注意,是先get再set,返回值是get的值,不返回set后的值
public final int getAndSetInt(Object var1, long var2, int var4) {
int var5;
do {
var5 = this.getIntVolatile(var1, var2);
} while(!this.compareAndSwapInt(var1, var2, var5, var4));

return var5;
}

//同上,只不过把类型变成long
public final long getAndSetLong(Object var1, long var2, long var4) {
long var6;
do {
var6 = this.getLongVolatile(var1, var2);
} while(!this.compareAndSwapLong(var1, var2, var6, var4));

return var6;
}

public final Object getAndSetObject(Object var1, long var2, Object var4) {
Object var5;
do {
var5 = this.getObjectVolatile(var1, var2);
} while(!this.compareAndSwapObject(var1, var2, var5, var4));

return var5;
}

类、对象、变量操作方法

  上述方法中都用到了偏移量,那么偏移量是如何获取的?Unsafe类中提供了很多关于对象、对象、变量的操作方法,可以让我们方便地获取目标字段的偏移量。

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 native long staticFieldOffset(Field var1);

//获取字段var1在示例对象中的偏移量
public native long objectFieldOffset(Field var1);

//返回值是f.getDeclaringClass()
public native Object staticFieldBase(Field var1);

//获得给定对象偏移量上的int值,所谓的偏移量可以简单理解为指针指向该变量的内存地址,通过偏移量便可得到该对象的变量,进行各种操作
public native int getInt(Object var1, long var2);

//设置给定对象上偏移量的int值
public native void putInt(Object var1, long var2, int var4);

//获得给定对象偏移量上的引用类型的值
public native Object getObject(Object var1, long var2);

//设置给定对象偏移量上的引用类型的值
public native void putObject(Object var1, long var2, Object var4);

//其他基本数据类型(long,char,byte,float,double)的操作与getInthe及putInt相同

//设置给定对象的int值,使用volatile语义,即设置后立马更新到内存对其他线程可见
public native void putIntVolatile(Object var1, long var2, int var4);

//获得给定对象的指定偏移量offset的int值,使用volatile语义,总能获取到最新的int值。
public native int getIntVolatile(Object var1, long var2);

//其他基本数据类型(long,char,byte,float,double)的操作与putIntVolatile及getIntVolatile相同,引用类型putObjectVolatile也一样。

//与putIntVolatile一样,但要求被操作字段必须有volatile修饰
public native void putOrderedInt(Object var1, long var2, int var4);

内存管理

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 native long allocateMemory(long bytes);

//根据给定的内存地址address设置重新分配指定大小的内存
public native long reallocateMemory(long address, long bytes);

//用于释放allocateMemory和reallocateMemory申请的内存
public native void freeMemory(long address);

//将指定对象的给定offset偏移量内存块中的所有字节设置为固定值
public native void setMemory(Object o, long offset, long bytes, byte value);

//设置给定内存地址的值
public native void putAddress(long address, long x);

//获取指定内存地址的值
public native long getAddress(long address);

//设置给定内存地址的long值
public native void putLong(long address, long x);

//获取指定内存地址的long值
public native long getLong(long address);

//设置或获取指定内存的byte值
public native byte getByte(long address);

public native void putByte(long address, byte x);
//其他基本数据类型(long,char,float,double,short等)的操作与putByte及getByte相同

//操作系统的内存页大小
public native int pageSize();

创建对象

  Unsafe还提供了新建对象的方法,需要注意的是该方法并不会调用对象的构造方法。所以创建对象的方式一共有5种,并不是流传最广的4种。

1
2

public native Object allocateInstance(Class cls) throws InstantiationException;

例子

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
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, InstantiationException {
Field field = Unsafe.class.getDeclaredField("theUnsafe");
field.setAccessible(true);
Unsafe unsafe = (Unsafe) field.get(null);


//通过allocateInstance创建对象
User user = (User) unsafe.allocateInstance(User.class);

Class userClass = user.getClass();
Field age = userClass.getDeclaredField("age");
Field name = userClass.getDeclaredField("name");
Field id = userClass.getDeclaredField("id");

unsafe.putInt(user, unsafe.objectFieldOffset(age), 18);
unsafe.putObject(user, unsafe.objectFieldOffset(name), "android TV");

Object staticFieldBase = unsafe.staticFieldBase(id);
System.out.println("staticBase:" + staticFieldBase);

//获取静态变量id的偏移量

long staticOffset = unsafe.staticFieldOffset(id);
System.out.println("设置前的ID:" + unsafe.getObject(staticFieldBase, staticOffset));
//此处需要使用staticFieldBase返回的结果
unsafe.putObject(staticFieldBase, staticOffset, "ssss");
//获取静态变量的值
System.out.println("设置前的ID:" + unsafe.getObject(staticFieldBase, staticOffset));
//输出USER
System.out.println("输出USER:" + user.toString());


long data = 1000;
byte size = 1;
long memeryAddress = unsafe.allocateMemory(size);
unsafe.putAddress(memeryAddress, data);
long addrData = unsafe.getAddress(memeryAddress);
System.out.println("addrData:"+addrData);
}

/**
输出结果

staticBase:class self.unsafe.User
设置前的ID:USE_ID
设置前的ID:ssss
输出USER:User{name='android TV', age=18, id=ssss'}
addrData:1000

*/
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
public class User {

public User() {
System.out.println("user 构造方法调用");
}


private String name;
private int age;
private static String id = "USE_ID";

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}

public static String getId() {
return id;
}

public static void setId(String id) {
User.id = id;
}

@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
", id=" + id + '\'' +
'}';
}
}

参考

  • Java并发编程-无锁CAS与Unsafe类及其并发包Atomic

java多线程实践-CountDownLatch

发表于 2018-06-27 | 分类于 java |
字数统计: | 阅读时长 ≈

  java多线程及并发包的知识点很多,在日常工作中很少用到,所以很难有较深刻的理解。这段时间计划深入学习一下juc,在深入源码前,先弄清楚每个类的用途,死记硬背不如找一个容易理解的例子来加深印象。

CountDownLatch

   CountDownLatch称之为闭锁,主要用于等待一组线程执行完毕再统一执行后面的程序,这样描述比较乏味难以记忆,在网上看到一个比较好的例子,拿过来分享一下。

例子

每天起早贪黑的上班,父母每天也要上班,话说今天定了个饭店,一家人一起吃个饭,通知大家下班去饭店集合。假设:3个人在不同的地方上班,必须等到3个人到场才能吃饭,用程序如何实现呢?

实现

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
public class LatchTest {

private static final CountDownLatch countDownLatch = new CountDownLatch(3);

public static void main(String[] args) throws InterruptedException {

new Thread() {
@Override
public void run() {
fatherToRes();
countDownLatch.countDown();
}
}.start();
new Thread() {
@Override
public void run() {
motherToRes();
countDownLatch.countDown();
}
}.start();
new Thread() {
@Override
public void run() {
meToRes();
countDownLatch.countDown();
}
}.start();

countDownLatch.await();
togetherToEat();


}

/**
* 模拟爸爸去饭店
*/
public static void fatherToRes() {
System.out.println("爸爸步行去饭店需要3小时。");
}

/**
* 模拟我去饭店
*/
public static void motherToRes() {
System.out.println("妈妈挤公交去饭店需要2小时。");
}

/**
* 模拟妈妈去饭店
*/
public static void meToRes() {
System.out.println("我乘地铁去饭店需要1小时。");
}

/**
* 模拟一家人到齐了
*/
public static void togetherToEat() {
System.out.println("一家人到齐了,开始吃饭");
}


}

总结

  这个小例子给人的印象深刻,一下就理解了如何使用闭锁。先学会用,接下来研究一下源码。

引用

  1. Java 并发专题 :闭锁 CountDownLatch 之一家人一起吃个饭
123…6
小建儿

小建儿

码农小白成长记

54 日志
8 分类
18 标签
RSS
© 2019 小建儿
本站访客数: |
| 博客全站共字