paulwong

2016年10月15日 #

使用 Docker 搭建 Java Web 运行环境

     摘要: Docker 是 2014 年最为火爆的技术之一,几乎所有的程序员都听说过它。Docker 是一种“轻量级”容器技术,它几乎动摇了传统虚拟化技术的地位,现在国内外已经有越来越多的公司开始逐步使用 Docker 来替换现有的虚拟化平台了。作为一名 Java 程序员,我们是时候一起把 Docker 学起来了!本文会对虚拟化技术与 Docker 容器技术做一个对比,然后引出一些 ...  阅读全文

posted @ 2016-10-15 19:57 paulwong 阅读(328) | 评论 (0)编辑 收藏

2016年9月16日 #

使用Spring Cloud Security OAuth2搭建授权服务

Spring Cloud Security OAuth2 是 Spring 对 OAuth2 的开源实现,优点是能与Spring Cloud技术线无缝集成,如果全部使用默认配置,开发者只需要添加注解就能完成 OAuth2 授权服务的搭建。

1. 添加依赖

授权服务是基于Spring Security的,因此需要在项目中引入两个依赖:

<dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-security</artifactId>
</dependency>

<dependency>
         <groupId>org.springframework.cloud</groupId>
         <artifactId>spring-cloud-starter-oauth2</artifactId>
 </dependency>


前者为 Security,后者为Security的OAuth2扩展。

2. 添加注解和配置

在启动类中添加@EnableAuthorizationServer注解:

@SpringBootApplication
@EnableAuthorizationServer
public class AlanOAuthApplication {
    public static void main(String[] args) {
        SpringApplication.run(AlanOAuthApplication.class, args);
    }
}


完成这些我们的授权服务最基本的骨架就已经搭建完成了。但是要想跑通整个流程,我们必须分配 client_idclient_secret才行。Spring Security OAuth2的配置方法是编写@Configuration类继承AuthorizationServerConfigurerAdapter,然后重写void configure(ClientDetailsServiceConfigurer clients)方法,如:

@Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory() // 使用in-memory存储
                .withClient("client") // client_id
                .secret("secret") // client_secret
                .authorizedGrantTypes("authorization_code") // 该client允许的授权类型
                .scopes("app"); // 允许的授权范围
    }


3. 授权流程

访问授权页面:

localhost:8080/oauth/authorize?client_id=client&response_type=code&redirect_uri=http://www.baidu.com


此时浏览器会让你输入用户名密码,这是因为 Spring Security 在默认情况下会对所有URL添加Basic Auth认证。默认的用户名为user, 密码是随机生成的,在控制台日志中可以看到。

oauth2

画风虽然很简陋,但是基本功能都具备了。点击Authorize后,浏览器就会重定向到百度,并带上code参数:

这里写图片描述

拿到code以后,就可以调用

POST/GET http://client:secret@localhost:8080/oauth/token
  • 1

来换取access_token了:

curl -X POST -H "Cache-Control: no-cache" -H "Content-Type: application/x-www-form-urlencoded" -d 'grant_type=authorization_code&code=Li4NZo&redirect_uri=http://www.baidu.com' "http://client:secret@localhost:8080/oauth/token"

返回如下:

{
  "access_token": "32a1ca28-bc7a-4147-88a1-c95abcc30556",
  "token_type": "bearer",
  "expires_in": 2591999,
  "scope": "app"
}

到此我们最最基本的授权服务就搭建完成了。然而,这仅仅是个demo,如果要在生产环境中使用,还需要做更多的工作。

4. 使用MySQL存储access_token和client信息

把授权服务器中的数据存储到数据库中并不难,因为 Spring Cloud Security OAuth 已经为我们设计好了一套Schema和对应的DAO对象。但在使用之前,我们需要先对相关的类有一定的了解。

4.1 相关接口

Spring Cloud Security OAuth2通过DefaultTokenServices类来完成token生成、过期等 OAuth2 标准规定的业务逻辑,而DefaultTokenServices又是通过TokenStore接口完成对生成数据的持久化。在上面的demo中,TokenStore的默认实现为InMemoryTokenStore,即内存存储。 对于Client信息,ClientDetailsService接口负责从存储仓库中读取数据,在上面的demo中默认使用的也是InMemoryClientDetialsService实现类。说到这里就能看出,要想使用数据库存储,只需要提供这些接口的实现类即可。庆幸的是,框架已经为我们写好JDBC实现了,即JdbcTokenStoreJdbcClientDetailsService

4.2 建表

要想使用这些JDBC实现,首先要建表。框架为我们提前设计好了schema, 在github上:https://github.com/spring-projects/spring-security-oauth/blob/master/spring-security-oauth2/src/test/resources/schema.sql

在使用这套表结构之前要注意的是,对于MySQL来说,默认建表语句中主键是varchar(255)类型,在mysql中执行会报错,原因是mysql对varchar主键长度有限制。所以这里改成128即可。其次,语句中会有某些字段为LONGVARBINARY类型,它对应mysql的blob类型,也需要修改一下。

4.3 配置

数据库建好后,下一步就是配置框架使用JDBC实现。方法还是编写@Configuration类继承AuthorizationServerConfigurerAdapter

@Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private DataSource dataSource;
    @Bean // 声明TokenStore实现
    public TokenStore tokenStore() {
        return new JdbcTokenStore(dataSource);
    }
    @Bean // 声明 ClientDetails实现
    public ClientDetailsService clientDetails() {
        return new JdbcClientDetailsService(dataSource);
    }
    @Override // 配置框架应用上述实现
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.authenticationManager(authenticationManager);
        endpoints.tokenStore(tokenStore());

        // 配置TokenServices参数
        DefaultTokenServices tokenServices = new DefaultTokenServices();
        tokenServices.setTokenStore(endpoints.getTokenStore());
        tokenServices.setSupportRefreshToken(false);
        tokenServices.setClientDetailsService(endpoints.getClientDetailsService());
        tokenServices.setTokenEnhancer(endpoints.getTokenEnhancer());
        tokenServices.setAccessTokenValiditySeconds( (int) TimeUnit.DAYS.toSeconds(30)); // 30天
        endpoints.tokenServices(tokenServices);
    }

完成这些后,框架就会将中间产生的数据写到mysql中了。oauth_client_details是client表,可以直接在该表中添加记录来添加client: 
这里写图片描述

4.4 需要注意的地方

这里不得不说 Spring 设计有一个奇葩地的方。注意看oauth_access_token表是存放访问令牌的,但是并没有直接在字段中存放token。Spring 使用OAuth2AccessToken来抽象与令牌有关的所有属性,在写入到数据库时,Spring将该对象通过JDK自带的序列化机制序列成字节直接保存到了该表的token字段中。也就是说,如果只看数据表你是看不出access_token的值是多少,过期时间等信息的。这就给资源服务器的实现带来了麻烦。我们的资源提供方并没有使用Spring Security,也不想引入 Spring Security 的任何依赖,这时候就只能将 DefaultOAuth2AccessToken的源码copy到资源提供方的项目中,然后读取token字段并反序列化还原对象来获取token信息。但是如果这样做还会遇到反序列化兼容性的问题,具体解决方法参考我另一篇博文:http://blog.csdn.net/neosmith/article/details/52539614

5. 总结

至此一个能在生产环境下使用的授权服务就搭建好了。其实我们在实际使用时应该适当定制JdbcTokenStoreClientDetailsService来实适应业务需要,甚至可以直接从0开始实现接口,完全不用框架提供的实现。另外,Spring 直接将DefaultOAuth2AccessToken序列化成字节保存到数据库中的设计,我认为是非常不合理的。或许设计者的初衷是保密access_token,但是通过加密的方法也可以实现,完全不应该直接扔字节。不过通过定制TokenStore接口,我们可以使用自己的表结构而不拘泥于默认实现。

http://blog.csdn.net/tracker_w/article/category/6360121

http://blog.csdn.net/neosmith/article/details/52539927

posted @ 2016-09-16 18:22 paulwong 阅读(804) | 评论 (0)编辑 收藏

使用Spring Cloud Feign作为HTTP客户端调用远程HTTP服务

在Spring Cloud Netflix栈中,各个微服务都是以HTTP接口的形式暴露自身服务的,因此在调用远程服务时就必须使用HTTP客户端。我们可以使用JDK原生的URLConnection、Apache的Http Client、Netty的异步HTTP Client, Spring的RestTemplate。但是,用起来最方便、最优雅的还是要属Feign了。

Feign简介

Feign是一种声明式、模板化的HTTP客户端。在Spring Cloud中使用Feign, 我们可以做到使用HTTP请求远程服务时能与调用本地方法一样的编码体验,开发者完全感知不到这是远程方法,更感知不到这是个HTTP请求。比如:

@Autowired
private AdvertGropRemoteService service; // 远程服务

public AdvertGroupVO foo(Integer groupId) {
    return service.findByGroupId(groupId); // 通过HTTP调用远程服务
}

开发者通过service.findByGroupId()就能完成发送HTTP请求和解码HTTP返回结果并封装成对象的过程。

Feign的定义

为了让Feign知道在调用方法时应该向哪个地址发请求以及请求需要带哪些参数,我们需要定义一个接口:

@FeignClient(name = "ea")  //  [A]
public interface AdvertGroupRemoteService {

    @RequestMapping(value = "/group/{groupId}", method = RequestMethod.GET) // [B]
    AdvertGroupVO findByGroupId(@PathVariable("groupId") Integer adGroupId) // [C]

    @RequestMapping(value = "/group/{groupId}", method = RequestMethod.PUT)
    void update(@PathVariable("groupId") Integer groupId, @RequestParam("groupName") String groupName)

A: @FeignClient用于通知Feign组件对该接口进行代理(不需要编写接口实现),使用者可直接通过@Autowired注入。

B: @RequestMapping表示在调用该方法时需要向/group/{groupId}发送GET请求。

C: @PathVariableSpringMVC中对应注解含义相同。

Spring Cloud应用在启动时,Feign会扫描标有@FeignClient注解的接口,生成代理,并注册到Spring容器中。生成代理时Feign会为每个接口方法创建一个RequetTemplate对象,该对象封装了HTTP请求需要的全部信息,请求参数名、请求方法等信息都是在这个过程中确定的,Feign的模板化就体现在这里。

在本例中,我们将Feign与Eureka和Ribbon组合使用,@FeignClient(name = "ea")意为通知Feign在调用该接口方法时要向Eureka中查询名为ea的服务,从而得到服务URL。

Feign的Encoder、Decoder和ErrorDecoder

Feign将方法签名中方法参数对象序列化为请求参数放到HTTP请求中的过程,是由编码器(Encoder)完成的。同理,将HTTP响应数据反序列化为java对象是由解码器(Decoder)完成的。

默认情况下,Feign会将标有@RequestParam注解的参数转换成字符串添加到URL中,将没有注解的参数通过Jackson转换成json放到请求体中。注意,如果在@RequetMapping中的method将请求方式指定为POST,那么所有未标注解的参数将会被忽略,例如:

@FeignClient(name = "ea")  //  [A]
public interface AdvertGroupRemoteService {

    @RequestMapping(value = "/group/{groupId}", method = RequestMethod.GET) // [B]
    AdvertGroupVO findByGroupId(@PathVariable("groupId") Integer adGroupId) // [C]

    @RequestMapping(value = "/group/{groupId}", method = RequestMethod.PUT)
    void update(@PathVariable("groupId") Integer groupId, @RequestParam("groupName") String groupName)

此时因为声明的是GET请求没有请求体,所以obj参数就会被忽略。

在Spring Cloud环境下,Feign的Encoder*只会用来编码没有添加注解的参数*。如果你自定义了Encoder, 那么只有在编码obj参数时才会调用你的Encoder。对于Decoder, 默认会委托给SpringMVC中的MappingJackson2HttpMessageConverter类进行解码。只有当状态码不在200 ~ 300之间时ErrorDecoder才会被调用。ErrorDecoder的作用是可以根据HTTP响应信息返回一个异常,该异常可以在调用Feign接口的地方被捕获到。我们目前就通过ErrorDecoder来使Feign接口抛出业务异常以供调用者处理。

Feign的HTTP Client

Feign在默认情况下使用的是JDK原生的URLConnection发送HTTP请求,没有连接池,但是对每个地址会保持一个长连接,即利用HTTP的persistence connection 。我们可以用Apache的HTTP Client替换Feign原始的http client, 从而获取连接池、超时时间等与性能息息相关的控制能力。Spring Cloud从Brixtion.SR5版本开始支持这种替换,首先在项目中声明Apache HTTP Client和feign-httpclient依赖:

@RequestMapping(value = "/group/{groupId}", method = RequestMethod.GET)
void update(@PathVariable("groupId") Integer groupId, @RequestParam("groupName") String groupName, DataObject obj);

然后在application.properties中添加:

feign.httpclient.enabled=true

总结

通过Feign, 我们能把HTTP远程调用对开发者完全透明,得到与调用本地方法一致的编码体验。这一点与阿里Dubbo中暴露远程服务的方式类似,区别在于Dubbo是基于私有二进制协议,而Feign本质上还是个HTTP客户端。如果是在用Spring Cloud Netflix搭建微服务,那么Feign无疑是最佳选择。

http://blog.csdn.net/tracker_w/article/category/6360121
http://blog.csdn.net/neosmith/article/details/52449921

posted @ 2016-09-16 18:13 paulwong 阅读(554) | 评论 (0)编辑 收藏

2016年9月11日 #

微服务框架Spring Cloud

2016

posted @ 2016-09-11 20:49 paulwong 阅读(267) | 评论 (0)编辑 收藏

JHipster

基于SPRING CLOUD的微服务框架
http://jhipster.cn/

posted @ 2016-09-11 16:40 paulwong 阅读(102) | 评论 (0)编辑 收藏

Spring Boot 性能优化

摘要
Spring 框架给企业软件开发者提供了常见问题的通用解决方案,包括那些在未来开发中没有意识到的问题。但是,它构建的 J2EE 项目变得越来越臃肿,逐渐被 Spring Boot 所替代。Spring Boot 让我们创建和运行项目变得更为迅速,现在已经有越来越多的人使用它。我们已经在几个项目中使用了 Spring Boot ,今天我们就来一起讨论一下如何改进 Spring Boot 应用的性能。

Spring 框架给企业软件开发者提供了常见问题的通用解决方案,包括那些在未来开发中没有意识到的问题。但是,它构建的 J2EE 项目变得越来越臃肿,逐渐被 Spring Boot 所替代。Spring Boot 让我们创建和运行项目变得更为迅速,现在已经有越来越多的人使用它。我们已经在几个项目中使用了 Spring Boot ,今天我们就来一起讨论一下如何改进 Spring Boot 应用的性能。

首先,从之前我在开发中遇到的一个问题说起。在一次查看项目运行日志的时候,我偶然发现了一个问题,日志里显示这个项目总是加载 Velocity 模板引擎,但实际上这个项目是一个没有 web 页面的 REST Service 项目。于是我花了一点时间去寻找产生这个问题的原因,以及如何改进 Spring Boot 应用的性能。在查找了相关的资料后,我得出的结论如下:

组件自动扫描带来的问题

默认情况下,我们会使用 @SpringBootApplication 注解来自动获取的应用的配置信息,但这样也会给应用带来一些副作用。使用这个注解后,会触发自动配置( auto-configuration )和 组件扫描 ( component scanning),这跟使用 @Configuration、@EnableAutoConfiguration 和 @ComponentScan 三个注解的作用是一样的。这样做给开发带来方便的同时,也会有两方面的影响:

1、会导致项目启动时间变长。当启动一个大的应用程序,或将做大量的集成测试启动应用程序时,影响会特别明显。

2、会加载一些不需要的多余的实例(beans)。

3、会增加 CPU 消耗。

针对以上两个情况,我们可以移除 @SpringBootApplication 和 @ComponentScan 两个注解来禁用组件自动扫描,然后在我们需要的 bean 上进行显式配置:

// 移除 @SpringBootApplication and @ComponentScan, 用 @EnableAutoConfiguration 来替代
@Configuration
@EnableAutoConfiguration
public class SampleWebUiApplication {

    
// 

    
// 用 @Bean 注解明确显式配置,以便被 Spring 扫描到
    @Bean
    
public MessageController messageController(MessageRepository messageRepository) {
        
return new MessageController(messageRepository);
    }

如何避免组件自动扫描带来的问题

我们在上面提到,@SpringBootApplication 注解的作用跟 @EnableAutoConfiguration 注解的作用是相当的,那就意味着它也能带来上述的三个问题。要避免这些问题,我们就要知道我们需要的组件列表是哪些,可以用 -Ddebug 的方式来帮助我们明确地定位:

mvn spring-boot:run -Ddebug … ========================= AUTO-CONFIGURATION REPORT =========================   Positive matches: -----------------     DispatcherServletAutoConfiguration       - @ConditionalOnClass classes found: org.springframework.web.servlet.DispatcherServlet (OnClassCondition)       - found web application StandardServletEnvironment (OnWebApplicationCondition)  ... 

接着拷贝 Positive matches 中列出的信息:

DispatcherServletAutoConfiguration 
EmbeddedServletContainerAutoConfiguration
ErrorMvcAutoConfiguration
HttpEncodingAutoConfiguration
HttpMessageConvertersAutoConfiguration
JacksonAutoConfiguration
JmxAutoConfiguration
MultipartAutoConfiguration
ServerPropertiesAutoConfiguration
PropertyPlaceholderAutoConfiguration
ThymeleafAutoConfiguration
WebMvcAutoConfiguration
WebSocketAutoConfiguration

然后来更新项目配置,显式地引入这些组件,引入之后,再运行一下应用确保没有错误发生:

@Configuration
@Import({
        DispatcherServletAutoConfiguration.
class,
        EmbeddedServletContainerAutoConfiguration.
class,
        ErrorMvcAutoConfiguration.
class,
        HttpEncodingAutoConfiguration.
class,
        HttpMessageConvertersAutoConfiguration.
class,
        JacksonAutoConfiguration.
class,
        JmxAutoConfiguration.
class,
        MultipartAutoConfiguration.
class,
        ServerPropertiesAutoConfiguration.
class,
        PropertyPlaceholderAutoConfiguration.
class,
        ThymeleafAutoConfiguration.
class,
        WebMvcAutoConfiguration.
class,
        WebSocketAutoConfiguration.
class,
})
public class SampleWebUiApplication {}


在上面的代码中,我们可以删掉我们不需要的组件信息,来提高应用的性能,比如在我的项目中,不需要 JMX 和 WebSocket 功能,我就删掉了它们。删掉之后,再次运行项目,确保一切正常。

将Servlet容器变成Undertow

默认情况下,Spring Boot 使用 Tomcat 来作为内嵌的 Servlet 容器。我们可以启动项目,然后用 VisualVM 或者 JConsole 来查看应用所占的内存情况:

Spring Boot 性能优化

以上是我使用 Spring Boot 的默认方式启动应用后,用 VisualVM 监控到的内存的占用情况:堆内存占用 110M,16 个线程被开启。

可以将 Web 服务器切换到 Undertow 来提高应用性能。Undertow 是一个采用 Java 开发的灵活的高性能 Web 服务器,提供包括阻塞和基于 NIO 的非堵塞机制。Undertow 是红帽公司的开源产品,是 Wildfly 默认的 Web 服务器。首先,从依赖信息里移除 Tomcat 配置:

<exclusions>
        
<exclusion>
                
<groupId>org.springframework.boot</groupId>
                
<artifactId>spring-boot-starter-tomcat</artifactId>
        
</exclusion>
</exclusions>


然后添加 Undertow:

<dependency>
        
<groupId>org.springframework.boot</groupId>
        
<artifactId>spring-boot-starter-undertow</artifactId>
</dependency>


启动项目后,用 VisualVM 监控到的信息显示:堆内存占用 90M,13个线程被开启。

Spring Boot 性能优化

总结

这些都是我们在项目开发中使用到的一些优化 Spring Boot 应用的小技巧,对于大的应用性能的提高还是很明显的。大家可以尝试一下,然后告诉我们你的测试结果。

最后,附上代码,大家可以去这里下载:spring-boot-performance

文中大部分内容参考英国一个架构师的博客 和 DZone 近期发布的文章,在此感谢两位大牛。参考文章及链接:

(1)Spring Boot 性能优化:Spring Boot Performance

(2)Spring Boot 内存优化:Spring Boot Memory Performance

(3)https://www.techempower.com/benchmarks/

(4)Spring 应用程序优化:Optimizing Spring Framework for App Engine Applications

posted @ 2016-09-11 16:37 paulwong 阅读(185) | 评论 (0)编辑 收藏

spring cloud项目读取配置管理

摘要
spring cloud config server配置好了数据库连接信息,这个项目读取config,获取连接信息。这里以mybtis作为列子。从服务器读取jdbc信息后,运行mybatis程序。

确认服务是否成功
http://localhost:8888/demo-config/test
{"name":"demo-config","profiles":["test"],"label":"master","version":"02d28ad4925aa9bd1bf8a48d2edbf04ce61aa45a","propertySources":[{"name":"https://git.oschina.net/penghaozhong/demo.git/demo-config-repo/demo-config-test.properties","source":{"jdbc.url":"jdbc:mysql://localhost:3306/demo?characterEncoding=UTF-8","jdbc.username":"root","jdbc.driver":"com.mysql.jdbc.Driver","jdbc.password":"xxxxxx","jdbc.type":"mysql"}}]}

    2. 配置读取配置文件

  



在bootstrap.properties中添加读取配置管理的地址。

3. 读取配置文件属性,这里采用@ConfigurationProperties
/**
 * 读取数据库配置文件
 * 
@author penghaozhong
 *
 
*/
@ConfigurationProperties(prefix = DataSourceProperties.PREFIX, ignoreUnknownFields = false)
public  class  DataSourceProperties {
    
        public DataSourceProperties() {
        super();
    }
        //对应配置文件里的配置键
        public final static String PREFIX="jdbc";    
        
        private String type; 
        private String driver; 
        private String url; 
        private String username; 
        private String password;
        
        public String getType() {
            return type;
        }
        public void setType(String type) {
            this.type = type;
        }
        public String getDriver() {
            return driver;
        }
        public void setDriver(String driver) {
            this.driver = driver;
        }
        public String getUrl() {
            return url;
        }
        public void setUrl(String url) {
            this.url = url;
        }
        public String getUsername() {
            return username;
        }
        public void setUsername(String username) {
            this.username = username;
        }
        public String getPassword() {
            return password;
        }
        public void setPassword(String password) {
            this.password = password;
        }

}


4. 配置mybatis
@Configuration
@MapperScan("com.phz.test.spring.cloud.demo")
@EnableConfigurationProperties(DataSourceProperties.class)
@EnableTransactionManagement
public class MybatisDataSource {

    // mybaits mapper xml搜索路径
    private final static String MAPPERLOCATIONS = "classpath:/mappings/**/*.xml";
    private final static String CONFIGLOCATION = "classpath:/mybatis-config.xml";

    @Autowired
    private  DataSourceProperties dataSourceProperties;
    private DruidDataSource datasource = null;

    @Bean(destroyMethod = "close")
    public  DataSource dataSource(){
        datasource = new DruidDataSource();  
        datasource.setUrl(dataSourceProperties.getUrl());
        datasource.setDbType(dataSourceProperties.getType());
        datasource.setDriverClassName(dataSourceProperties.getDriver());
        datasource.setUsername(dataSourceProperties.getUsername());
        datasource.setPassword(dataSourceProperties.getPassword());
        return datasource;
    }

    @PreDestroy
    public void close() {
        if(datasource != null){
            datasource.close();
        }
    }

    @Bean
    public SqlSessionFactory sqlSessionFactoryBean() throws Exception {
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(dataSource());
        PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        sqlSessionFactoryBean.setMapperLocations(resolver.getResources(MAPPERLOCATIONS));
        sqlSessionFactoryBean.setConfigLocation(resolver.getResource(CONFIGLOCATION));
        sqlSessionFactoryBean.setTypeAliasesPackage("com.phz.test.spring.cloud.demo.entity");
        return sqlSessionFactoryBean.getObject();
    }

    @Bean
    public PlatformTransactionManager transactionManager() {
        return new DataSourceTransactionManager(dataSource());
    }

}











posted @ 2016-09-11 16:26 paulwong 阅读(200) | 评论 (0)编辑 收藏

spring-loaded热部署

什么是spring-loaded?

spring-loaded是一个对于jvm代理运行时期改变类文件的重载(重新加载),它转换类loadtime让他们服从后重新加载。不像“热代码替换”只允许一次简单的改变JVM运行(例如更改方法体)spring-loaded允许您添加/修改/删除/字段/方法构造函数。注释类型/方法/字段/构造函数也可以修改和可以添加/删除/修改值的枚举类型。

有什么好处?

开发测试阶段:能够在启动后动态更改代码调试,无需重启减少切换debug时间(ps:对于eclipse而言,在debug时期只能做到动态更新方法体不能增加)
对于线上测试发布阶段: 能够在出现问题后直接替换class文件而不重启应用(ps:对于外部提供的服务jar形式同样能做到)
怎么使用?

项目地址

https://github.com/spring-projects/spring-loaded

第一步:下载文件
http://repo.spring.io/release/org/springframework/springloaded/1.2.5.RELEASE/springloaded-1.2.5.RELEASE.jar

第二步:配置jvm启动参数

eclipse
eclipse:run as --> run configurations --> arguments -->> VM arguments
-javaagent:E:\repository\org\springframework\spring-load\springloaded-1.2.5.RELEASE.jar 
-noverify -Dspringloaded=verbose
详细描述:
-javaagent: 配置java代理使用下载后的jar包路径
-noverify: 禁用字节码验证
-Dspringloaded=verbose 显示springloaded时的详细信息


image

java命令启动

java -javaagent:E:\repository\org\springframework\spring-load\springloaded-1.2.5.RELEASE.jar -noverify Test  类似 

java jar包动态替换

1.打成runnable Jar
2.命令启动:

java -javaagent:E:\repository\org\springframework\spring-load\springloaded-1.2.5.RELEASE.jar -noverify -Dspringloaded=watchJars=main.jar main.jar

/**  * 类Test.java的实现描述:TODO 类实现描述   * @author Administrator 2016年7月4日 下午4:55:59  */ public class Test {     public static void main(String[] args) throws InterruptedException {          while(true) {             try {                 println();                 Thread.sleep(1000);             } catch (Throwable e) {                  e.printStackTrace();              }          }       }     public static void println() {          System.out.println("112222221222222");          }  } 

改变为

/**  * 类Test.java的实现描述:TODO 类实现描述   * @author Administrator 2016年7月4日 下午4:55:59  */ public class Test {     public static void main(String[] args) throws InterruptedException {          while(true) {             try {                 println();                 Thread.sleep(1000);             } catch (Throwable e) {                  e.printStackTrace();              }          }       }     public static void println() {          System.out.println("test replace jar");          }  } 
3.重新打包替换
PS:实测在window下无用 手上无linux机器待测试




1

posted @ 2016-09-11 10:40 paulwong 阅读(224) | 评论 (0)编辑 收藏

2016年9月1日 #

MICROSERVICE 资源

Spring Cloud 为开发者提供了在分布式系统(如配置管理、服务发现、断路器、智能路由、微代理、控制总线、一次性 Token、全局锁、决策竞选、分布式会话和集群状态)操作的开发工具。使用 Spring Cloud 开发者可以快速实现上述这些模式。

主要有eureka做服务发现、config做分布式配置、zuul做api-gateway、feign做客户端负载均衡、hystrix做断路器、turbine做聚合的monitor、graphite做指标监控。

http://blog.csdn.net/liaokailin/article/category/6212338


MICROSERVICE WITH SPRING-CLOUD.
https://github.com/kennyk65/Microservices-With-Spring-Student-Files




!!!spring-cloud-study
http://git.oschina.net/itmuch/spring-cloud-study

posted @ 2016-09-01 21:46 paulwong 阅读(88) | 评论 (0)编辑 收藏

2016年6月5日 #

Disruptor

一个ring buffer实现多线程通信。由于他们之间通信不需要锁所以性能有很大的提高。

Disruptor更多的应用在高速事务中,利用JVM的伪内存,这也可能是它为LMAX而生的,和akka的应用场景不一样。

一般编写并发应用程序马上想到多线程或者多进程。但多线程需要处理资源竞争,共享访问等问题,搞不好容易出现死锁,当程序规模比较大时,排查难度很大。 Actor模型提供了另一种编写并发应用程序的思路。 有点类似Node.JS的基于事件异步处理. (其实我觉得基于消息异步和基于事件异步是一回事)

什么是基于消息异步呢?很简单,比如要开展一个项目,需要多人协作。作为项目经理的你,只需要像手下发出命令,个人各干各的,互不干扰。做完了就回送一个消息给项目经理,项目经理再分派新的任务. (可能比喻得不恰当,但Actor的基本思路就是这样,你不需要考虑资源共享和线程并发什么的, Actor库屏蔽了这些底层的实现细节 . 每个Actor就相当于一个人或者叫一个处理者,他们的职责很单一,就是响应对方发来的消息,做出响应,并回送一个响应消息。 每个Actor负责做自己的份内事,最后有一个调度角色的Actor将所有Actor管理起来,形成一个整体)

Akka 是针对Scala和Java的Actor库,JActor是一个用纯Java编写的Actor库。 

https://github.com/LMAX-Exchange/disruptor
http://www.oschina.net/p/disruptor

posted @ 2016-06-05 18:19 paulwong 阅读(163) | 评论 (0)编辑 收藏

仅列出标题  下一页