• jrebel使用


    背景与愿景:开发环境下,tomcat对热布署的支持还不够全面,致使开发人员浪费大量时间在重起服务上。为了提高开发效率,决定引入Jrebel,它对热布署的支持相对比较全面。虽然Jrebel官方号称使用它不存在内存泄漏问题,但是占用一定的资源是肯定的,因此不考虑在正式环境下使用热布署。Jrebel实际上支持非常多中间件,除了Tomcat还包括Jetty、Resin、Weblogic等等,从理论上来讲,他跟中间件也没什么关系,但实际配置的时候还是会根据中间件有所不同,具体可以上官网查看,本文要讲的是tomcat+ eclipse+ spring+ struts2+ maven的环境。在使用Jrebel后,我们期望看到开发人员早上开机启动一次tomcat后就够了。本文的前置文章m2eclipse+tomcat实现应用布署,点击进入http://truemylife.iteye.com/blog/1669031

    使用场景:Tomcat对热布署的使用场景是Servlet+JSP+JaveBean。如果项目含有其他框架时,其热布署效果就会大大降低,在与同事一同测试观察后发现:tomcat6在spring+struts框架下的项目,对java文件修改后的成功热布署概率偏低。由于概率太低,而且有无热布署成功不能确定,大部分开发人员修改类后不管什么情况直接选择重起,长此以往,浪费的时间积累起来不在少数。下面把tomcat和jrebel对热布署测试结果对比一下:

    对比项

    Jrebel

    Tomcat

    Class文件

    绝大部分能热布署

    小部分能热布署

    Spring支持

    改成用注释的方式后,可支持

    不支持

    Struts配置文件

    支持

    支持

    页面相关文件

    支持

    支持

    从对比可以看到,Jrebel最大的提升是对java类修改时,热布署大大提高;而对spring的支持实际上还是有限的,需要把IoC的实现改成使用注释的方式,而不能是配置的方式。如果你的工程的Spring已经是注释的方式,那就比较顺利,装好插件后,绝大部分情况下都能使用热布署了。如果你不是使用注释方式,那就麻烦了,要么全都改成注释方式,要么Jrebel对spring作用有限,看你自己的选择了。下面把已知Jrebel不能成功的热布署的情况作一列举:

    1、替换了父类。

    2、增加或删除了继承的接口。

    3、Spring布署文件修改(如果改成注释方式,实际上spring只剩个别固定的第三方包的beans描述,比如数据库链接等)

    4、web.xml,虽然jrebel和tomcat都支持web.xml修改的热布署,但是如果项目比较复杂,初始化工作较多的话,还是直接重起吧,直接热布署意义不大,而且重复初始化对于某些业务来说是会报错,所以建议有较复杂的初始化项目来说,还是直接重起得了。

    Jrebel安装和使用

    1、jrebel是商用软件,而且价格不扉,去下载个破解版吧,最新的破解版是4.0,如果网上找不到,请留下邮件。下载jrebel.jar到本地,比如放在d:jrebel.jar

    2、Eclipse window->preference->tomcat->JVM Settings,加入以下参数

    -Drebel.spring_plugin=true 支持spring框架

    -Drebel.aspectj_plugin=true 支持aspectj

    -Drebel.struts2_plugin=true 支持strut2

    -javaagent:D:jrebel.jar 这里自行修改jrebel.jar正确的路径

    -noverify

    如果你要支持更多的框架,可以参考官网http://www.zeroturnaround.com/jrebel/features/frameworks/

    如果你要了解更多的参数配置,可以参考官网

    http://www.zeroturnaround.com/jrebel/configuration/

        jrebel支持监控多个目录下的classes、配置文件、jar包是否被修改,因此建议新建并配置rebel.xml文件,如果Eclipse安装了官网的jrebel plugin,那么可以从eclipse菜单里产生rebel.xml文件。以下是rebel.xml的简单手动配置:

    <?xml version="1.0" encoding="UTF-8"?>

    <application

      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

      xmlns="http://www.zeroturnaround.com"

      xsi:schemaLocation="http://www.zeroturnaround.com/alderaan/rebel-2_0.xsd">

      <classpath>

        <dir name="E:projectscmac argetclasses"/>

        <dir name="E:projectscmac arget est-classes"/>

      </classpath>

      <web>

        <link target="/">

          <dir name="E:projectscmacsrcmainwebapp"/>

        </link>

      </web>

    </application>

    rebel.xml更详细配置说明参考官网(http://www.zeroturnaround.com/jrebel/configuration/)

    3、此时启动tomcat,会发现如下错误信息

    严重: Exception starting filter Struts2

    java.lang.NoClassDefFoundError: Lorg/apache/velocity/app/VelocityEngine;

             at java.lang.Class.getDeclaredFields0(Native Method)

             at java.lang.Class.privateGetDeclaredFields(Class.java:2291)

             at java.lang.Class.getDeclaredFields(Class.java:1743)

             at com.opensymphony.xwork2.inject.ContainerImpl.addInjectors(ContainerImpl.java:102)

             at com.opensymphony.xwork2.inject.ContainerImpl$1.create(ContainerImpl.java:84)

             at com.opensymphony.xwork2.inject.ContainerImpl$1.create(ContainerImpl.java:82)

             at com.opensymphony.xwork2.inject.util.ReferenceCache$CallableCreate.call(ReferenceCache.java:155)

             at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)

             at java.util.concurrent.FutureTask.run(FutureTask.java:138)

             at com.opensymphony.xwork2.inject.util.ReferenceCache.internalCreate(ReferenceCache.java:81)

             at com.opensymphony.xwork2.inject.util.ReferenceCache.get(ReferenceCache.java:121)

             at com.opensymphony.xwork2.inject.ContainerImpl$ConstructorInjector.<init>(ContainerImpl.java:333)

             at com.opensymphony.xwork2.inject.ContainerImpl$5.create(ContainerImpl.java:299)

             at com.opensymphony.xwork2.inject.ContainerImpl$5.create(ContainerImpl.java:298)

             at com.opensymphony.xwork2.inject.util.ReferenceCache$CallableCreate.call(ReferenceCache.java:155)

             at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)

             at java.util.concurrent.FutureTask.run(FutureTask.java:138)

             at com.opensymphony.xwork2.inject.util.ReferenceCache.internalCreate(ReferenceCache.java:81)

             at com.opensymphony.xwork2.inject.util.ReferenceCache.get(ReferenceCache.java:121)

             at com.opensymphony.xwork2.inject.ContainerImpl.getConstructor(ContainerImpl.java:578)

             at com.opensymphony.xwork2.inject.ContainerImpl.inject(ContainerImpl.java:476)

             at com.opensymphony.xwork2.inject.ContainerImpl$7.call(ContainerImpl.java:517)

             at com.opensymphony.xwork2.inject.ContainerImpl.callInContext(ContainerImpl.java:565)

             at com.opensymphony.xwork2.inject.ContainerImpl.inject(ContainerImpl.java:515)

             at com.opensymphony.xwork2.config.impl.LocatableFactory.create(LocatableFactory.java:32)

             at com.opensymphony.xwork2.inject.ContainerBuilder$4.create(ContainerBuilder.java:135)

             at com.opensymphony.xwork2.inject.Scope$2$1.create(Scope.java:49)

             at com.opensymphony.xwork2.inject.ContainerImpl$ParameterInjector.inject(ContainerImpl.java:447)

             at com.opensymphony.xwork2.inject.ContainerImpl.getParameters(ContainerImpl.java:462)

             at com.opensymphony.xwork2.inject.ContainerImpl.access$000(ContainerImpl.java:48)

             at com.opensymphony.xwork2.inject.ContainerImpl$MethodInjector.inject(ContainerImpl.java:288)

             at com.opensymphony.xwork2.inject.ContainerImpl$2.call(ContainerImpl.java:117)

             at com.opensymphony.xwork2.inject.ContainerImpl$2.call(ContainerImpl.java:115)

             at com.opensymphony.xwork2.inject.ContainerImpl.callInContext(ContainerImpl.java:558)

             at com.opensymphony.xwork2.inject.ContainerImpl.injectStatics(ContainerImpl.java:114)

             at com.opensymphony.xwork2.inject.ContainerBuilder.create(ContainerBuilder.java:495)

             at com.opensymphony.xwork2.config.impl.DefaultConfiguration.reloadContainer(DefaultConfiguration.java:170)

             at com.opensymphony.xwork2.config.ConfigurationManager.getConfiguration(ConfigurationManager.java:55)

             at org.apache.struts2.dispatcher.Dispatcher.init_PreloadConfiguration(Dispatcher.java:371)

             at org.apache.struts2.dispatcher.Dispatcher.init(Dispatcher.java:424)

             at org.apache.struts2.dispatcher.FilterDispatcher.init(FilterDispatcher.java:213)

             at org.apache.catalina.core.ApplicationFilterConfig.initFilter(ApplicationFilterConfig.java:273)

             at org.apache.catalina.core.ApplicationFilterConfig.getFilter(ApplicationFilterConfig.java:254)

             at org.apache.catalina.core.ApplicationFilterConfig.setFilterDef(ApplicationFilterConfig.java:372)

             at org.apache.catalina.core.ApplicationFilterConfig.<init>(ApplicationFilterConfig.java:98)

             at org.apache.catalina.core.StandardContext.filterStart(StandardContext.java:4562)

             at org.apache.catalina.core.StandardContext$2.call(StandardContext.java:5240)

             at org.apache.catalina.core.StandardContext$2.call(StandardContext.java:5235)

             at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)

             at java.util.concurrent.FutureTask.run(FutureTask.java:138)

             at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)

             at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)

             at java.lang.Thread.run(Thread.java:619)

    Caused by: java.lang.ClassNotFoundException: org.apache.velocity.app.VelocityEngine

             at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1676)

             at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1521)

             at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:316)

             ... 53 more

    竟然报出需要velocity相关包,那好吧,我的项目是用maven来做管理的,在pom.xml里加上相关依赖如下:

    <dependency>

        <groupId>org.apache.velocity</groupId>

        <artifactId>velocity</artifactId>

        <version>1.7</version>

        </dependency>

        <dependency>

        <groupId>org.apache.velocity</groupId>

        <artifactId>velocity-tools</artifactId>

        <version>2.0</version>

    </dependency>

    再次重起tomcat后,一切正常,可以看到jrebel关键信息在console里输出:

    JRebel: Directory 'E:projectscmac argetclasses' will be monitored for changes.

    JRebel: Directory 'E:projectscmac arget est-classes' will be monitored for changes.

    JRebel: Directory 'E:projectscmacsrcmainwebapp' will be monitored for changes.

    4、如果你使用maven发布并启动tomcat,那么需要安装jrebel-maven-plugin。本文前面提到只是满足开发阶段而且启动tomcat方式不是使用mvn命令方式,因此不需要安装jrebel-maven-plugin。

    Spring利用注释方式实现IoC

        现在大部分java项目有使用Spring框架,为了能使Jrebel更好的对Spring相关资源发生热布署作用,就得充分使用注释的方式实现依赖注入。这里对Spring实现注释方式作一下最简单的介绍,首先在applicationContext.xml里配置如下两行代码:

    <context:annotation-config/> 

    <context:component-scan base-package="*"/>

    简单的说,以上的配置让spring支持了我们将要实现的注释依赖注入。以下以登录为实例,按action层、业务层、数据库操作层、PO层分别新建四个类:

    LoginAction.java//struts action

    UserServiceImpl.java//business layer

    UserDaoImpl.java//dao layer

    User.java //pojo

    那么怎样通过注释方式进行调用的呢,首先给要被调用的类加上@Component注释,Spring为了区分不同层次的类,分别定义了以下四种注释

    @Reposity

    @Service

    @Controller

    @Component

    目前阶段这四个注释实际上效果是一样的,我们约定如下:PO类如有需要使用@Reposity注释;Dao和Service使用@Service注释;Action使用@Controller注释;剩余分不出层次的类使用@Component注释。

    如本例,action、service、dao分别加上注释

    @Scope("prototype")

    @Controller("loginAction")

    public class LoginAction extends BaseAction{

    }

    @Service("userService")

    public class UserServiceImpl implements UserService{

    }

    @Service("userDao")

    public class UserDaoImpl extends BaseDao implements UserDao{

    }

    Scope注释默认是singleton,可以缺省。使用这四个标签时,如果不使用参数值,那么spring会按自己规范取名,比如LoginAction,使用@Controller()注释,默认取名为loginAction。取好了名,相当于在配置文件里配置了一组bean,接下来看怎么注入依赖,比如LoginAction要调用UserService,代码片段如下:

    @Scope("prototype")

    @Controller("loginAction")

    public class LoginAction extends BaseAction{

    @Autowired

    Private UserService userService

    }

    就这么简单,添加xwork.xml配置,新加跳转页面,这些操作统统不用重起服务。

    弹出Continue or Terminate疑问

        装上jrebel后,可以进入你的tomcat/conf/context.xml或server.xml,其中有一个参数reload=true,把它改成false。表示关闭tomcat自身的热布署,在eclipse里启动tomcat,修改了类,有时还是会弹出Continue or Terminate框,难道是个Bug?不得而知。不过有jrebel在不用担心,继续continue,会发现你的修改是有效的。只有碰到前面提到的不适合jrebel热布署的场景时,即使没弹出Continue or Terminate提示框,你也要自己重起服务。

    Jrebel官方对热布署支持的场景列表(查看官网说明http://www.zeroturnaround.com/jrebel/features/)

    Java EE Support

    Jrebel

    JVM Hot Swap

    Time to reload

    < 1s

    < 1s

    No memory leak

    YES

    YES

     

    Changes to method bodies

    YES

    YES

    Adding/removing Methods

    YES

    NO

    Adding/removing constructors

    YES

    NO

    Adding/removing fields

    YES

    NO

    Adding/removing classes

    YES

    NO

    Adding/removing annotations

    YES

    NO

    Changing static field value

    YES JRebel 3.0+

    NO

    Adding/removing enum values

    YES JRebel 3.0+

    NO

    Changing interfaces

    YES

    NO

    Replacing superclass

    NO

    NO

    Adding/removing implemented interfaces

    NO

    NO

     

    Skip builds for WAR directories

    YES

    YES

    Skip builds for .WAR/.EAR class updates

    YES

    YES

    Skip builds for .WAR/.EAR resource updates

    YES

    NO

    Map multiple source dirs to one .WAR/.EAR target dir

    YES

    NO

    Map classes and resources with include/exclude patterns

    YES

    NO

    Map multiple source dirs with Ant-style patterns

    YES

    NO

    Use system properties to make mapping machine-independent

    YES

    NO

    Maven plugin

    YES

    NO

    JSP EL changes

    YES

    NO

    JSP Scriptlet changes

    YES Enterprise Add-on

    NO

    EJB 1.x session bean interface changes

    YES Enterprise Add-on

    NO

    EJB 2.x session bean interface changes

    YES Enterprise Add-on

    NO

    EJB 3.x session bean interface changes

    YES JRebel 3.0+

    NO

    JSF changes (Mojarra)

    YES JRebel 3.0+

    NO

    JPA changes (Hibernate, EclipseLink, TopLink, OpenJPA)

    YES JRebel 3.0+

    NO

    CDI changes (Weld)

    YES JRebel 3.0+

    NO

    ResourceBundle

    YES

    NO

    Spring Framework 2.x or later

    YES

    NO

    Hibernate

    YES JRebel 3.0+

    NO

    JBoss Seam 2.x or later

    YES JRebel 3.0+

    NO

    Google Guice

    YES

    NO

    Stripes 1.x or later

    YES

    NO

    Apache log4j 1.2.x or later

    YES

    NO

    Apache Struts 1.x

    YES

    NO

    Apache Struts 2.x or later

    YES

    NO

    Apache Tapestry4

    YES

    NO

    Apache Velocity

    YES

    NO

    Apache Wicket

    YES

    NO

    CgLib

    YES JRebel 3.0+

    NO

    Javassist

    YES JRebel 3.0+

    NO

    Atlassian Confluence plugins

    YES

    NO

    ClassWorlds

    YES Beta

    NO

    Apache Felix

    YES Beta

    NO

    Eclipse Equinox

    YES Beta

    NO

    IntelliJ IDEA 7.x, 8.x plugins

    YES Beta

    NO

    NetBeans plugins

    YES Beta

    NO

    Jrebel对第三方框架支持对应表

    查看官网http://www.zeroturnaround.com/jrebel/features/frameworks/

  • 相关阅读:
    OpenSergo & CloudWeGo 共同保障微服务运行时流量稳定性
    开源小白到核心开发——我与 sealer 的成长故事
    Serverless 架构下的 AI 应用开发:入门、实战与性能优化
    KubeVela 1.5:灵活框选 CNCF 原子能力打造独特的企业应用发布平台
    全链路灰度新功能:MSE 上线配置标签推送
    提质增效,安全灵活,阿里云EDA上云方案让芯片设计驶入高速路
    极致体验!基于阿里云 Serverless 快速部署 Function
    企业分账如何帮助用户解决成本优化和预算分配的问题
    我们总结了弹性伸缩的五个条件与六个教训
    数据变更白屏化利器推送轨迹上线
  • 原文地址:https://www.cnblogs.com/soundcode/p/6594854.html
Copyright © 2020-2023  润新知