视频

Maven 增强

使用 maven 增强模块增强实体和查询 Bean

IntelliJ 插件

使用 IntelliJ IDEA 插件进行增强

IntelliJ 调试器

查看调用延迟加载的 Idea 调试器设置

Eclipse 插件

使用 Eclipse 插件进行增强

Eclipse APT

Eclipse 设置,用于查询 Bean 生成(通过 Java 注解处理器)。

建议

同时使用 IDE 插件增强(Idea 或 Eclipse)和构建时增强。

对于 IntelliJ IDEA 和 Eclipse 用户,我的建议是除了构建时增强(maven 插件)或代理外,还要使用 IDE 插件。

也就是说,IDE 插件在开发期间很好用,可以在 IDE 编译类时增强 Bean。使用 IDE 插件可以减少开发和单元测试期间的增强麻烦。对于生产,您可以在构建时增强(例如 maven)或运行时增强(例如 javaagent)之间进行选择。

概述

术语“增强”涵盖了用于修改实体 Bean 的所有方式(javaagent、ant、maven、IDE 插件等)。用于描述增强的其他术语包括“编织”、“转换”和“字节码操作”。

加载时编织用于指在“加载时”通常通过 javaagent 发生类操作,而类操作在“构建时”通常通过 Maven、Ant 或 IDE 插件发生。

从原始意义上讲,类是一个 byte[],增强是在类由其 ClassLoader 定义之前操作这些字节。

使用多个增强器

Ebean 增强会意识到增强何时已经发生。通过这种方式,通常且预期可以同时使用多种形式的增强,例如同时使用 IDE 插件和 maven 插件来执行增强。

Maven 增强

Maven 插件在 maven 编译过程中执行增强。这可以描述为“构建时增强”。

Maven 增强模块

Ebean 提供了一个 maven 模块,它同时引入了实体 Bean 的增强器和查询 Bean 的增强。这比以传统(非模块)方式定义插件更简单、更简洁、更简洁,现在是首选方法。

ebean 增强模块为以下内容带来插件配置
  • 实体 bean 和 @Transactional 增强(适用于主模块和测试)
  • 查询 bean 增强(适用于主模块和测试)
  • ebean-codegen 插件,用于生成查找器等
ebean 增强图块
<plugin>
  <groupId>io.repaint.maven</groupId>
  <artifactId>tiles-maven-plugin</artifactId>
  <version>2.22</version>
  <extensions>true</extensions>
  <configuration>
    <tiles>
      <!-- other tiles ... -->
      <tile>io.ebean.tile:enhancement:13.25.0</tile>
    </tiles>
  </configuration>
</plugin>

使用 mvn help:effective-pom 查看图块引入的插件。

Maven 插件

如果您不想使用 maven 图块,则可以以“普通”方式指定 maven 增强插件。请注意,与图块不同,这不会引入 查询 bean 增强

<plugin>
  <groupId>io.ebean</groupId>
  <artifactId>ebean-maven-plugin</artifactId>
  <version>${version}</version>
  <executions>
    <execution>
      <id>main</id>
      <phase>process-classes</phase>
      <configuration>
        <transformArgs>debug=1</transformArgs>
      </configuration>
      <goals>
        <goal>enhance</goal>
      </goals>
    </execution>
  </executions>
</plugin>

Eclipse + Maven 增强

可以使用 maven 配置在构建期间配置 Eclipse 以增强类

<build>
  <plugins>
    <!-- plugins here -->
  </plugins>
  <pluginManagement>
    <plugins>
      <!--This plugin's configuration is used to store Eclipse m2e settings only. It has no influence on the Maven build itself. -->
      <plugin>
        <groupId>org.eclipse.m2e</groupId>
        <artifactId>lifecycle-mapping</artifactId>
        <version>1.0.0</version>
        <configuration>
          <lifecycleMappingMetadata>
            <pluginExecutions>
              <pluginExecution>
                <pluginExecutionFilter>
                  <groupId>io.ebean</groupId>
                  <artifactId>ebean-maven-plugin</artifactId>
                  <versionRange>[${version},)</versionRange>
                  <goals>
                    <goal>enhance</goal>
                  </goals>
                </pluginExecutionFilter>
                <action>
                  <execute>
                    <runOnConfiguration>true</runOnConfiguration>
                    <runOnIncremental>true</runOnIncremental>
                  </execute>
                </action>
              </pluginExecution>
            </pluginExecutions>
          </lifecycleMappingMetadata>
        </configuration>
      </plugin>
    </plugins>
  </pluginManagement>
</build>

代理

您可以根据以下示例在命令行上使用 javaagent 参数。这通常被称为“运行时增强”或“加载时增强”。

请注意,从 ebean-agent 4.7.1 版本开始,预计该代理将在不指定要增强的包的情况下良好运行。也就是说,该代理非常擅长忽略不感兴趣的类(JDK、groovy、scala、kotlin、jdbc 驱动程序以及来自 apache、google、testing 等的许多常见库)。

java -javaagent:ebean-agent-${version}.jar MyApplication
java -javaagent:ebean-agent-${version}.jar=debug=3 MyApplication

可以从 maven 下载 ebean-agent jar。当前版本为

<dependency>
  <groupId>${groupid}</groupId>
  <artifactId>${artifactid}</artifactId>
  <version>${version_str}</version>
</dependency>
<dependency org="${groupid}" name="${artifactid}" rev="${version_str}"/>
@Grapes(
  @Grab(group='${groupid}', module='${artifactid}', version='${version_str}')
)
'${groupid}:${artifactid}:${version_str}'
'${groupid}:${artifactid}:${version_str}'
libraryDependencies += "${groupid}" % "${artifactid}" % "${version_str}"
[${groupid}/${artifactid} "${version_str}"]

代理加载器

不建议使用代理加载器

代理加载器可用于以编程方式将 javaagent 加载到正在运行的 JVM 上。但是,这偶尔不会增强 bean,因为实体 bean 类在 JVM 上加载代理之前已加载,因此不建议采用此方法。

请注意,此方法用于 Ebean 本身的测试代码中,如果您使用此方法,则需要确保在加载任何实体 bean 或事务 bean 的类之前加载代理。

<dependency>
  <groupId>${groupid}</groupId>
  <artifactId>${artifactid}</artifactId>
  <version>${version_str}</version>
</dependency>
<dependency org="${groupid}" name="${artifactid}" rev="${version_str}"/>
@Grapes(
  @Grab(group='${groupid}', module='${artifactid}', version='${version_str}')
)
'${groupid}:${artifactid}:${version_str}'
'${groupid}:${artifactid}:${version_str}'
libraryDependencies += "${groupid}" % "${artifactid}" % "${version_str}"
[${groupid}/${artifactid} "${version_str}"]

以下代码以编程方式将增强器代理加载到正在运行的 JVM 上。

import org.avaje.agentloader;
...
public void someApplicationBootupMethod() {
  // Load the agent into the running JVM process
  if (!AgentLoader.loadAgentFromClasspath("ebean-agent","debug=1;packages=org.example.model")) {
    logger.info("ebean-agent not found in classpath - not dynamically loaded");
  }
}

Ant 增强

修改 ant build.xml 文件为

  1. 定义 AntEnhanceTask。
  2. 创建一个使用 AntEnhanceTask 增强实体类的目标。
<taskdef
    name="ebeanEnhance"
    classname="io.ebean.enhance.ant.AntEnhanceTask"
    classpath="your_path_to/ebean-x.x.x.jar"/>

<target name="ormEnhance" depends="clean,compile">
  <!--
  classSource: This is the directory that contains your class files. That is, the directory where your IDE will compile your java class files to, or the directory where a previous ant task will compile your java class files to.

  packages: a comma delimited list of packages that contain entity classes. All the classes in these packages are searched for entity classes to be enhanced. transformArgs: This contains a debug level (0 - 10) .
  -->
  <ebeanEnhance
      classSource="your_classes_directory"
      packages="app.domain.*"
      transformArgs="debug=1"/>
</target>

以编程方式增强

您可以使用代理中的 Transformer 类以编程方式自己运行增强。

Transformer transformer = new Transformer("", "debug=1");
InputStreamTransform streamTransform = new InputStreamTransform(transformer, Ebean.class.getClassLoader());

// Or use ASM or Javassist get bytecode and new InputSream
// eg. in = new ByteArrayInputStream(ctClass.toBytecode());
InputStream in = new URL("your.class.file.class").openStream();

byte[] result = null;
try {
  result = streamTransform.transform("your.class.name", in);//class must be not loaded by classLoader
} finally {
  in.close();
}
if (result == null) {
  throw new CannotCompileException("ebean enhance model fail!");
}
defineClass("your.class.name", result, 0, result.length);