Sam's Notes | Sam Blog

梦想还是要有的,万一实现了呢

0%

部门权限控制

  • 认证 权限 由 shiro 控制, 部门范围由具体业务处理

很多现代语言都有 GC ,与 GC 紧密相关的是对象的引用。

Java

Java有4种引用类型:

  • 强引用 StrongReference: 平常使用的都是这种,其他引用统称 弱引用

    强引用可以直接访问目标对象。
    强引用所指向的对象在任何时候都不会被系统回收。
    强引用可能导致内存泄漏。

1
Bean bean = new Bean();
  • 软引用 SoftReference: 最强的弱引用, 内存紧缺时可能会被GC回收。

    软引用使用 get() 方法取得对象的强引用从而访问目标对象。
    软引用所指向的对象按照 JVM 的使用情况(Heap 内存是否临近阈值)来决定是否回收。
    软引用可以避免 Heap 内存不足所导致的异常。

1
SoftReference<Bean> bean = new SoftReference<Bean>(new Bean());
  • 弱引用 WeakReference :

    弱引用使用 get() 方法取得对象的强引用从而访问目标对象。
    一旦系统内存回收,无论内存是否紧张,弱引用指向的对象都会被回收。
    弱引用也可以避免 Heap 内存不足所导致的异常。

1
WeakReference<Bean> bean = new WeakReference<Bean>(new Bean());
  • 虚引用 PhantomReference: 始终是null
1
2
ReferenceQueue<Bean> refQueue = new ReferenceQueue<Bean>();
PhantomReference<Bean> referent = new PhantomReference<Bean>(new Bean(), refQueue);

有篇可以参照 blog

Swift

Swift 使用自动引用计数(ARC)机制来跟踪和管理你的应用程序的内存。
Swift有3种引用类型:

  • 强引用 StrongReference: ARC + 1,ARC 不会销毁被引用的实例
1
2
3
class Person {
var apartment: Apartment?
}
  • 弱引用 WeakReference : 弱引用不会对其引用的实例保持强引用,因而不会阻止 ARC 销毁被引用的实例。
1
2
3
class Apartment {
weak var tenant: Person?
}
  • 无主引用 unowned : 无主引用是永远有值的。总是被定义为非可选类型(non-optional type)。总是可以被直接访问。

    1
    2
    3
    4
    5
    6
    7
    class Customer {
    var card: CreditCard?
    }
    class CreditCard {
    unowned let customer: Customer
    }

  • 无主引用以及隐式解析可选属性

    1
    2
    3
    4
    5
    6
    7
    class Country {
    var capitalCity: City!
    }

    class City {
    unowned let country: Country
    }

Person和Apartment的例子展示了两个属性的值都允许为nil,并会潜在的产生循环强引用。这种场景最适合用弱引用来解决。

Customer和CreditCard的例子展示了一个属性的值允许为nil,而另一个属性的值不允许为nil,这也可能会产生循环强引用。这种场景最适合通过无主引用来解决。

Country和City的例子中两个属性都必须有值,并且初始化完成后永远不会为nil。在这种场景中,需要一个类使用无主属性,而另外一个类使用隐式解析可选属性。

更详细的内容可以参考 中译 Swift

今天用到了 activiti 5.16;它依赖 org.restlet.jee:org.restlet:2.2.1 等 jar。奇怪的事情发现了, 一向运行良好的 nexus 出问题,org.restlet.jee:org.restletxxx:2.2.1 一系列的jars都无法下载。这里吐草下,org.restlet.jee:org.restletxxx 看着就别扭,so nexus 也找不到它,自然也无法下载。
解决方案如下:

  • 增加restlet的Repository
    管理员账户登录nexus 控制台, 增加restlet的Repository,类型为proxy

    具体内容参照下图,重要 Remote Storage Location 设置为 http://maven.restlet.com/

  • restlet 加入 Public repositories group
    加入前
    加入后

  • 清除本地 Repositories
    别忘了删除 maven 的本地 repositories 里的 restlet 文件夹。

上篇介绍了 集成Spring-远程调用, 本次介绍集成 Spring, 常规JMS,消息驱动。主角是 activeMq, JmsTemplate, @JmsListener。

  • activeMq 是消息总线,JMS provider;
  • JmsTemplate 是由 Spring提供的消息模板,简化消息生产者和消费者端的代码开发量。就是封装了 连接JMS provider(如ActiveMQ),建立JMS Session(如QueueSession),建立消息生产者,建立消费者,发送消息,接收消息;
  • @JmsListener 由 Spring 提供的最简单的消息接收端操作方式。

准备

必须的jar

maven管理的方式

1
2
3
4
5
6
7
8
9
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-all</artifactId>
<version>5.12.0</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>

activemq 的 PooledConnectionFactory 会调用 commons-pool2。

PropertySourcesPlaceholderConfigurer

配置PropertySourcesPlaceholderConfigurer, 下面用得着,比较优雅。

1
2
3
4
5
6
7
8
9
@Configuration
public class ApplicationConfiguration
{
//To resolve ${} in @Value (in *.properties files by @PropertySource included)
@Bean
public static PropertySourcesPlaceholderConfigurer propertyConfigInDev() {
return new PropertySourcesPlaceholderConfigurer();
}
}

配置

消息生产者和消费者都需要。

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
import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.activemq.command.ActiveMQQueue;
import org.apache.activemq.pool.PooledConnectionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.jms.annotation.EnableJms;
import org.springframework.jms.config.DefaultJmsListenerContainerFactory;
import org.springframework.jms.connection.CachingConnectionFactory;
import org.springframework.jms.core.JmsTemplate;

@Configuration
@EnableJms //开启jsm 注解
@PropertySource({ "classpath:conf/jms.properties"}) // 加载配置资源文件
public class JmsConfiguration
{

@Autowired
private Environment env;

//ConnectionFactory
@Bean
public ActiveMQConnectionFactory jmsConnectionFactory()
{
ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory();
connectionFactory.setBrokerURL("tcp://localhost:61616");
return connectionFactory;
}

//activeMq PooledConnectionFactory
@Bean
public PooledConnectionFactory activeMqPooledConnectionFactory()
{
PooledConnectionFactory jmsFactory = new PooledConnectionFactory();
jmsFactory.setConnectionFactory(jmsConnectionFactory());
return jmsFactory;
}

//spring CachingConnectionFactory
@Bean
public CachingConnectionFactory springCachingConnectionFactory()
{
CachingConnectionFactory jmsFactory = new CachingConnectionFactory();
jmsFactory.setTargetConnectionFactory(jmsConnectionFactory());
return jmsFactory;
}

// Queue
@Bean
public ActiveMQQueue jmsQueue()
{
ActiveMQQueue queue = new ActiveMQQueue(env.getProperty("testQueue"));
return queue;
}

// ListenerContainerFactory, @EnableJms 需要这个默认 bean
@Bean
public DefaultJmsListenerContainerFactory jmsListenerContainerFactory() {
DefaultJmsListenerContainerFactory factory =
new DefaultJmsListenerContainerFactory();
factory.setConnectionFactory(activeMqPooledConnectionFactory());
factory.setConcurrency("3-10");
return factory;
}

// Spring jmsTemplate
@Bean
public JmsTemplate myJmsTemplate()
{
JmsTemplate jmsTp = new JmsTemplate();
jmsTp.setDefaultDestination(jmsQueue());
jmsTp.setConnectionFactory(activeMqPooledConnectionFactory());
return jmsTp;
}
}

补充说明:

  • @EnableJms:开启 JMS 注解, 这样 @JmsListener 等注解才会生效;默认需要jmsListenerContainerFactory 这个 Bean。
  • activeMq PooledConnectionFactory 和 springCachingConnectionFactory 同等作用,可以替换。
  • testQueue 具体value 在 jms.properties 里配置,类似常量。

消息发送和接收

首先看代码

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
@Service("GmGameAchvServiceImpl")
@PropertySource({ "classpath:conf/jms.properties"})
public class GmGameAchvServiceImpl
{
@Resource(name = "myJmsTemplate")
private JmsTemplate jmsTemplate;


// 消息接收
@JmsListener(destination = "${testQueue}")
public void JmsReceiveTest(String data)
{
System.out.println("jms ----------------------------- " + data);
}


//消息发送
public void jmsSendTest()
{
int numberOfMessages = 10;
StringBuilder payload = null;
for (int i = 0; i < numberOfMessages; ++i)
{
payload = new StringBuilder();
payload.append("Message [").append(i).append("] sent at: ").append(new Date());
final int finalI = i;
final StringBuilder finalPayload = payload;
jmsTemplate.send((Session session) -> {
TextMessage message = session.createTextMessage(finalPayload.toString());
message.setIntProperty("messageCount", finalI);
return message;
});


}
}
  • 消息发送
    方法 jmsSendTest, 利用 jmsTemplate 很方便
  • 消息接收
    JmsReceiveTest, 使用了 @JmsListener,这是最简单的方式,比 jmsTemplate 更简单。
    @JmsListener 需要制定 destination, 这里 ${testQueue} 的值由 conf/jms.properties 里具体制定, 由上文提到的 PropertySourcesPlaceholderConfigurer 负责转化。 如此在一个配置文件里配置,多个地方使用,如需改动,仅需修改配置文件,不用修改源代码。

消息数据转换 Message Converters

Spring 会自动进行消息转换, 比如上面 jmsSendTest 发送的是 TextMessageJmsReceiveTest 用 String 类型参数接收就好。POJO 对象一样可以如此操作。

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
@JmsListener(destination = "${testQueue}")
public void JmsReceiveTest(GmGameAchvEntity data)
{
System.out.println("jms ----------------------------- " + data.getId());
}

@Override
public void jmsSendTest()
{
int numberOfMessages = 10;
StringBuilder payload = null;
for (int i = 0; i < numberOfMessages; ++i)
{
final int finalI = i;
GmGameAchvEntity achv = new GmGameAchvEntity();
achv.setId((long) i);
jmsTemplate.send((Session session) -> {
ObjectMessage message = session.createObjectMessage(achv);
message.setIntProperty("messageCount", finalI);
return message;
});
}
}

如此这般就好了,是不是 很简单方便。

响应管理

1
2
3
4
5
6
@JmsListener(destination = "myQueue")
@SendTo("queueOut")
public OrderStatus processOrder(Order order) {
// order processing
return status;
}

@SendTo 就可以返回值 到 queueOut 这个destination

~~~~~~~ 嗯嗯, 很不错的样子 :)

activemq集合贴

上篇介绍了 activemq 的安装和使用,这篇介绍下集成 spring 最简单的运用,远程调用。注意,这种方式是没有事务控制的。

加入activemq 的 jar

maven 方式

1
2
3
4
5
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-all</artifactId>
<version>5.12.0</version>
</dependency>

辅助类

  • 接口(服务端和客户端都要有)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    public interface IGmGameAchvService
    {
    /**
    * 根据ID获取对象
    * @param companyId
    * @return
    */
    GmGameAchvEntity findById(Long id);
    }
  • 实现(服务端)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    @Service("GmGameAchvServiceImpl")
    public class GmGameAchvServiceImpl implements IGmGameAchvService
    {

    @Override
    public GmGameAchvEntity findById(Long id)
    {
    GmGameAchvEntity achv = new GmGameAchvEntity();
    achv.setId(1L);
    return achv;
    }
    }

配置

概要

如下内容服务端和客户端都需要配置
1 jmsConnectionFactory
2 jmsQueue

服务端另需配置
3 MessageListenerContainer
4 ServiceExporter

客户端另需配置
5 ProxyFactoryBean

具体内容

以下都是java based的配置,xml的配置可以参考 Spring doc

  • jmsConnectionFactory jmsQueue
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Configuration
public class JmsConfiguration
{

@Bean
public ActiveMQConnectionFactory jmsConnectionFactory(){
ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory();
connectionFactory.setBrokerURL("tcp://localhost:61616");
return connectionFactory;
}


@Bean
public ActiveMQQueue jmsQueue(){
ActiveMQQueue queue = new ActiveMQQueue("spring-activemq");
return queue;
}
}
  • 服务端

    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
    @Configuration
    public class JmsServerConfiguration
    {

    @Autowired
    private IGmGameAchvService gameAchvService;

    @Autowired
    private ActiveMQConnectionFactory jmsConnectionFactory;

    @Autowired
    private ActiveMQQueue jmsQueue;

    @Bean
    public JmsInvokerServiceExporter service()
    {
    JmsInvokerServiceExporter service = new JmsInvokerServiceExporter();
    service.setServiceInterface(IGmGameAchvService.class);
    service.setService(gameAchvService);

    return service;
    }

    @Bean
    public SimpleMessageListenerContainer msgListenerContainer()
    {
    SimpleMessageListenerContainer msgListenerContainer = new SimpleMessageListenerContainer();
    msgListenerContainer.setConnectionFactory(jmsConnectionFactory);
    msgListenerContainer.setDestination(jmsQueue);
    msgListenerContainer.setConcurrentConsumers(3);
    msgListenerContainer.setMessageListener(service());
    return msgListenerContainer;
    }
    }

  • 客户端
    配置

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    @Configuration
    public class JmsClientConfiguration
    {
    @Autowired
    private ActiveMQConnectionFactory jmsConnectionFactory;

    @Autowired
    private ActiveMQQueue jmsQueue;

    @Bean
    public JmsInvokerProxyFactoryBean achvService()
    {
    JmsInvokerProxyFactoryBean service = new JmsInvokerProxyFactoryBean();
    service.setServiceInterface(IGmGameAchvService.class);
    service.setConnectionFactory(jmsConnectionFactory);
    service.setQueue(jmsQueue);
    return service;
    }

    }

调用

1
2
3
4
5
6
7
8
9
10
11
IGmGameAchvService gmservice = (IGmGameAchvService) service;
GmGameAchvEntity achv = gmservice.findById(1L);
if (achv == null)
{
System.out.println("achv is null");
}
else
{
System.out.println("achv id=" + achv.getId());
}

监控

正常启动后, 在 activemq 的监控中可以看到相应内容。

Queues
connections

activemq集合贴

整理一些常用的服务器知识,配置和使用实例。这里仅作简单介绍。
陆续更新。。。

  • tomcat
    使用最广泛的 Web 应用服务器和 servlet 容器,不多说了。

  • tomEE(发音同“tommy”)
    完全兼容tomcat,从名字看就知道和tomcat关系密切。TomEE仅仅是Tomcat的一个扩展版本,任何能在Tomcat上使用的工具,如像Eclipse WTP一样的IDE工具,全部都能用在TomEE上。 TomEE=Tomcat+java EE,TomEE嵌入了EJB、CDI和其他JavaEE特征到Tomcat里,是一个完整符合Web Profile的服务器。

  • [nginx](/2016/01/22/web server/nginx/nginx/)
    是一个高性能的 HTTP 和 反向代理 服务器,也是一个 IMAP/POP3/SMTP 服务器。基本用的是前面的功能 :)

  • wildfly(Jboss as)
    JBoss Application Server(JBoss AS) 改名成 wildfly, 版本升级真快。提供完整的Java EE 栈。开源免费。

  • jetty
    开源的servlet容器

陆续更新。。。

1. 集成测试,是否测试上2个版本?

不仅测试本次发布版本功能,还需测试上2个版本在最新服务端接口上是否功能正常(git flow master库)

2. 上线测试,是否进行了小范围正式环境和数据测试。

Android可用友盟或自定义自动升级,iOS可用邀请测试,指定人员测试

3. 权限测试,是否进行权限极限测试

关闭APP需要的所以权限,测试每项功能。

以下全是linux系统上的操作,在opensuse 13.2 上实际操作。

准备

  • JDK 1.6 以上
  • JAVA_HOME 配置好
  • 官网

安装

  • 1 下载 activemq gzip 文件

    1
    $ wget http://ftp.meisei-u.ac.jp/mirror/apache/dist/activemq/5.12.0/apache-activemq-5.12.0-bin.tar.gz
  • 2 解压缩

    1
    $ tar zxvf activemq-x.x.x.tar.gz
  • 3 确认权限
    确认activemq 是否有执行权限

    1
    2
    $ cd [activemq_install_dir]/bin
    $ chmod 755 activemq

启动

进入安装目录的bin路径,启动activemq

1
2
$ cd [activemq_install_dir]/bin
$ ./activemq start

正常输出

1
2
3
4
INFO: Loading '[activemq_install_dir]/bin/env'
INFO: Using java '/usr/lib64/jvm/java/bin/java'
INFO: Starting - inspect logfiles specified in logging.properties and log4j.properties to get details
INFO: pidfile created : '[activemq_install_dir]/data/activemq.pid' (pid 'xxxx')

监控

网页监控 http://localhost:8161/admin
默认用户密码 admin/admin

可以在 conf/jetty-real.properties 中修改

端口

  • 网页监控
    端口: 8161
    配置: [activemq_install_dir]/conf/jetty.xml

  • activeMq 服务
    openwire: 61616
    amqp : 5672
    stomp : 61613
    mqtt : 1883
    ws : 61614
    配置: [activemq_install_dir]/conf/activemq.xml

停止

1
2
$ cd [activemq_install_dir]/bin
$ ./activemq stop

配置

[activemq_install_dir]/conf/activemq.xml

集群

集群

web demo

官网说 启动 activemq 后, http://localhost:8161/demo直接能访问, 其实5.12.0版本是不行的,不行的,不行的。

需要在 conf/jetty 中增加配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<bean class="org.eclipse.jetty.webapp.WebAppContext">
<property name="contextPath" value="/admin" />
<property name="resourceBase" value="${activemq.home}/webapps/admin" />
<property name="logUrlOnStart" value="true" />
</bean>


<!-- 需要增加 -->
<bean class="org.eclipse.jetty.webapp.WebAppContext">
<property name="contextPath" value="/demo" />
<property name="resourceBase" value="${activemq.home}/webapps-demo/demo/" />
<property name="logUrlOnStart" value="true" />
</bean>


...

重启activemq, http://localhost:8161/demo可以访问了, enjoy it !

activemq集合贴

几个消息总线(龟速更新。。。)

ActiveMQ

是Apache出品,最流行的,能力强劲的开源消息总线。ActiveMQ 是一个完全支持JMS1.1和J2EE 1.4规范的JMS Provider实现。

Kafka

由LinkedIn开发的一个分布式的消息系统,开源贡献给了Apache

Apollo

ActiveMQ的升级版,重新改写了内核,速度飞快,功能目前还不完全。

RabbitMQ

RabbitMQ是实现AMQP(高级消息队列协议)的消息中间件。Erlang语言编写的。

常用Message Queue对比 (转载 info 郭俊)

  • RabbitMQ

RabbitMQ是使用Erlang编写的一个开源的消息队列,本身支持很多的协议:AMQP,XMPP, SMTP, STOMP,也正因如此,它非常重量级,更适合于企业级的开发。同时实现了Broker构架,这意味着消息在发送给客户端时先在中心队列排队。对路由,负载均衡或者数据持久化都有很好的支持。

  • Redis

Redis是一个基于Key-Value对的NoSQL数据库,开发维护很活跃。虽然它是一个Key-Value数据库存储系统,但它本身支持MQ功能,所以完全可以当做一个轻量级的队列服务来使用。对于RabbitMQ和Redis的入队和出队操作,各执行100万次,每10万次记录一次执行时间。测试数据分为128Bytes、512Bytes、1K和10K四个不同大小的数据。实验表明:入队时,当数据比较小时Redis的性能要高于RabbitMQ,而如果数据大小超过了10K,Redis则慢的无法忍受;出队时,无论数据大小,Redis都表现出非常好的性能,而RabbitMQ的出队性能则远低于Redis。

  • ZeroMQ

ZeroMQ号称最快的消息队列系统,尤其针对大吞吐量的需求场景。ZeroMQ能够实现RabbitMQ不擅长的高级/复杂的队列,但是开发人员需要自己组合多种技术框架,技术上的复杂度是对这MQ能够应用成功的挑战。ZeroMQ具有一个独特的非中间件的模式,你不需要安装和运行一个消息服务器或中间件,因为你的应用程序将扮演这个服务器角色。你只需要简单的引用ZeroMQ程序库,可以使用NuGet安装,然后你就可以愉快的在应用程序之间发送消息了。但是ZeroMQ仅提供非持久性的队列,也就是说如果宕机,数据将会丢失。其中,Twitter的Storm 0.9.0以前的版本中默认使用ZeroMQ作为数据流的传输(Storm从0.9版本开始同时支持ZeroMQ和Netty作为传输模块)。

  • ActiveMQ

ActiveMQ是Apache下的一个子项目。 类似于ZeroMQ,它能够以代理人和点对点的技术实现队列。同时类似于RabbitMQ,它少量代码就可以高效地实现高级应用场景。

  • Kafka/Jafka

Kafka是Apache下的一个子项目,是一个高性能跨语言分布式发布/订阅消息队列系统,而Jafka是在Kafka之上孵化而来的,即Kafka的一个升级版。具有以下特性:快速持久化,可以在O(1)的系统开销下进行消息持久化;高吞吐,在一台普通的服务器上既可以达到10W/s的吞吐速率;完全的分布式系统,Broker、Producer、Consumer都原生自动支持分布式,自动实现负载均衡;支持Hadoop数据并行加载,对于像Hadoop的一样的日志数据和离线分析系统,但又要求实时处理的限制,这是一个可行的解决方案。Kafka通过Hadoop的并行加载机制统一了在线和离线的消息处理。Apache Kafka相对于ActiveMQ是一个非常轻量级的消息系统,除了性能非常好之外,还是一个工作良好的分布式系统

薪水之外,工程师最应该关系的问题

你们的企业文化是什么?

可以问问企业从开发到测试都喜欢什么工具,询问开发流程,询问工程和其他团队之间的关系。建议问“在应对项目时,你们公司会给开发人员什么级别的自主性?”

如何衡量我?

你的雇主如何定义你的“成功”?不同公司的评判标准不同,要满足你觉得不舒服的目标会让你的生活苦不堪言。

有什么成长计划?

询问是否有一个针对软件工程师的成长计划,询问一下,多少外部聘请 vs 公司内部晋升。

你们的发展计划?

你需要了解他们的发展计划,建议可以问这样的问题,如“你们的资金消耗率(公司的负现金流)是多少?”

我会喜欢你们的人吗?

聊到目前的团队成员,试着和公司的内部人士聊天(面试官以外),以便于知道公司内部管理人员大致的情形, “他们好合作吗,他们做事征求意见吗,他们提供反馈吗,他或她投资团队成员并帮助他们成长吗?”