print all data in paginated table/grid

direct Tabular data display

Recently our project has a page need to show tabular data from 30-6000 rows with 3-4 columns. At first, I thought this is pretty reasonable data to show in one page so I just throw the data into a ng-repeat table with my own implementation of filtering/sorting which is pretty straightforward in angular. Every time user select new category/type, fetch data from backend and replace the data in vm/$scope. Also with this implementation, it is quite easy to fulfill our another requirement which is export/print the page content. For export I just need to get the DOM content to the server and return as downloadable. For print, even easier, just call window.print() ,that’s it.

Performance issue with IE

Everything works fine until  our QA hits IE which is super slow when the data in the list is replaced from backend. Did some profiling in IE11, turns out the appendChild and removeChild calls are taking forever when it tries to clear the rows in the dom and put the new elements into dom. Also another slowness is from styleCalculation which it does for every column/row. Overall, IE takes 20s to render a page with 5000 rows and FF/safari/chrome need only 1-2 seconds. This forces us to abandon the straightforward way to use the more IE friendly way which is pagination with angular ui-grid. But this brings us to another problem which is print since data is now paginated and DOM only has 20 rows.

Server side render and client side print

What I eventually did is sending the model data back to server and do server side rendering and eventually send back to browser where an iFrame is created on the fly for printing. The pros of doing this is we have a lot of flexibility on content/layout by whatever manipulation/styling etc… The cons is we added more stuff to the stack and one more round trip comparing to the direct print.

server side

So on server side, when we get the REST call for print, we have a Thymeleaf template there for generating the html. I compared different java server side rendering engines like Velocity/Freemaker/Rythm etc, looks like Thymeleaf has the best Spring integration and most active development/release.

@Configuration
public class ThymeleafConfig
{
    @Autowired
    private Environment env;

    @Bean
    @Description("Thymeleaf template rendering HTML ")
    public ClassLoaderTemplateResolver exportTemplateResolver() {
        ClassLoaderTemplateResolver exportTemplateResolver = new ClassLoaderTemplateResolver();
        exportTemplateResolver.setPrefix("thymeleaf/");
        exportTemplateResolver.setSuffix(".html");
        exportTemplateResolver.setTemplateMode("HTML5");
        exportTemplateResolver.setCharacterEncoding(CharEncoding.UTF_8);
        exportTemplateResolver.setOrder(1);
        //for local development, we do not want template being cached so that we could do hot reload.
        if ("local".equals(env.getProperty("APP_ENV")))
        {
            exportTemplateResolver.setCacheable(false);
        }
        return exportTemplateResolver;
    }

    @Bean
    public SpringTemplateEngine templateEngine() {
        final SpringTemplateEngine engine = new SpringTemplateEngine();
        final Set<ITemplateResolver> templateResolvers = new HashSet<>();
        templateResolvers.add(exportTemplateResolver());
        engine.setTemplateResolvers(templateResolvers);
        return engine;
    }
}

With the engine we confined, we could used like:

            Context context = new Context();
            context.setVariable("firms", firms);
            context.setVariable("period", period);
            context.setVariable("rptName", rptName);
            context.setVariable("hasFirmId", hasFirmId);
            if (hasFirmId)
            {
                context.setVariable("firmIdType", FirmIdType.getFirmIdType(maybeFirmId).get());
            }

            return templateEngine.process("sroPrint", context);

Template with name sroPrint has some basic Theymleaf directives:

<html xmlns:th="http://www.thymeleaf.org">
<head>
<style>
    table thead tr th, table tbody tr td {
      border: 1px solid black;
      text-align: center;
    }
  </style>

</head>
<body>
<div>
<h4 th:text="${rptName}">report name</h4>
<div style="margin: 10px 0;"><b>Period:</b> <span th:text="${period}"></span>
<div>
  <h4 th:text="${rptName}">report name</h4>
  <div style="margin: 10px 0;"><b>Period:</b> <span th:text="${period}"></span></div>
  <table style="width: 100%; ">
    <thead>
    <tr>
      <th th:if="${hasFirmId}" th:text="${firmIdType}"></th>
      <th>crd #</th>
      <th>Firm Name</th>
    </tr>
    </thead>
    <tbody>
    <tr th:each="firm : ${firms}">
      <td th:if="${hasFirmId}" th:text="${firm.firmId}"></td>
      <td th:text="${firm.crdId}">CRD</td>
      <td th:text="${firm.firmName}">firm name</td>
    </tr>
    </tbody>
  </table>
</div>
</body>
</html>

client side

Now on the client side we need to consume the HTML string from the client side. The flow is we create an iFrame, write the html into it and call browser print on that iFrame and remove the element from DOM. The below implementation is inside the success callback of $http call for getting that dom string. It is in pure js without jQuery, with which it might be a bit more concise.


var printIFrame = document.createElement('iframe');
document.body.appendChild(printIFrame);
printIFrame.style.position = 'absolute';
printIFrame.style.top = '-9999px';
printIFrame.style.left = '-9999px';
var frameWindow = printIFrame.contentWindow || printIFrame.contentDocument || printIFrame;
var wdoc = frameWindow.document || frameWindow.contentDocument || frameWindow;
wdoc.write(res.data);
// tell browser write finished
wdoc.close();
$scope.$emit('UNLOAD');
// Fix for IE : Allow it to render the iframe
frameWindow.focus();
try {
    // Fix for IE11 - printng the whole page instead of the iframe content
    if (!frameWindow.document.execCommand('print', false, null)) {
        // document.execCommand returns false if it failed -http://stackoverflow.com/a/21336448/937891
        frameWindow.print();
    }
    // focus body as it is losing focus in iPad and content not getting printed
    document.body.focus();
}
catch (e) {
    frameWindow.print();
}
frameWindow.close();
setTimeout(function() {
    printIFrame.parentElement.removeChild(printIFrame);
}, 0);

PDF/XLS Export

For xls/pdf export, it is similar to the other POST that I have before. The only difference is the dom string was passed from client there. Here we generate the dom string in server side.

Advertisements

Spring nested @Transactional rollback only

Recently we get some odd xxx Thread got an uncaught exception in Nagios alters. and the corresponding exception in log is :

Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Transaction marked as rollbackOnly org.springframework.transaction.TransactionSystemException: Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Transaction marked as rollbackOnly
    at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:521)
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:754)
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:723)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:393)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:120)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:622)
    at methodA()...

Turns out the reason is we have a nested method also marked @Transactional and some exception happened inside which causes Spring marked it as RollBackonly in the thread local TransactionStatus.

@Transactional
public void outterMethod(){

 try{
  A a = new A();
  somedao.persist(a)
  ...
  nestedMethodWithTransationalAndHadExceptionInsde();
  ...}
 catch{
  //HERE, transaction is already marked as rollback only!
  somedao.merge(a);
 }
}

So the possible solution is:

  • remove the @Transacional from the nested method if it does not really require transaction control. So even it has exception, it just bubbles up and does not affect transactional stuff.
  • if nested method does need transaction control, make it as REQUIRE_NEW for the propagation policy that way even if throws exception and marked as rollback only, the caller will not be affected.

One caveat is :

Only unchecked exceptions (that is, subclasses of java.lang.RuntimeException) are rollbacked by default. For the case, a checked exception is thrown, the transaction will be committed!

And one customization can be done very easily by just adding the parameter rollBackFor to the @Transactional attribute:

@Transactional(rollbackFor = Exception.class)

Some source code from spring transactional implementation:

1. the Transaction abstraction

public interface PlatformTransactionManager {
    TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException;
    void commit(TransactionStatus status) throws TransactionException;
    void rollback(TransactionStatus status) throws TransactionException;
}

2. The TransactionDefinition

public interface TransactionDefinition {
    // Propagations
    int PROPAGATION_REQUIRED = 0;
    int PROPAGATION_SUPPORTS = 1;
    int PROPAGATION_MANDATORY = 2;
    int PROPAGATION_REQUIRES_NEW = 3;
    int PROPAGATION_NOT_SUPPORTED = 4;
    int PROPAGATION_NEVER = 5;
    int PROPAGATION_NESTED = 6;
    // Isolations
    int ISOLATION_DEFAULT = -1;
    int ISOLATION_READ_UNCOMMITTED = Connection.TRANSACTION_READ_UNCOMMITTED;
    int ISOLATION_READ_COMMITTED = Connection.TRANSACTION_READ_COMMITTED;
    int ISOLATION_REPEATABLE_READ = Connection.TRANSACTION_REPEATABLE_READ;
    int ISOLATION_SERIALIZABLE = Connection.TRANSACTION_SERIALIZABLE;
    // timeout
    int TIMEOUT_DEFAULT = -1;

    // behaviors
    int getPropagationBehavior();
    int getIsolationLevel();
    int getTimeout();
    boolean isReadOnly();
    String getName();
}

3. the TransactionStatus

public interface TransactionStatus extends SavepointManager, Flushable {
    boolean isNewTransaction();
    boolean hasSavepoint();
    void setRollbackOnly();
    boolean isRollbackOnly();
    void flush();
    boolean isCompleted();
}

A Chinese article about the source code.

 

logback spring boot rolling 配置

日志的配置

Spring Boot支持各种日志工具, 最常用的是Logback. 我们可以对日志进行配置, 由于日志是在ApplicationContext创建之前初始化的, 所以对日志的配置不能通过在@Configuration配置类上使用@PropertySources注解加载进来. 可以使用系统变量或者外部配置application.properties来加载. 配置文件中可以指定这些属性:

  • logging.config=: 配置文件的位置, 比如:classpath:logback.xml(logback的配置文件)
  • logging.file=: 日志文件名, 如:myapp.log, 输出日志到当前目录的myapp.log文件
  • logging.path=: 日志文件位置, 如:/var/log, 输出日志到/var/log/spring.log文件
  • logging.level.*=: 日志等级, 如:logging.level.org.springframework=DEBUG
  • logging.pattern.console=: 输出到console的日志格式, 只有logback有效
  • logging.pattern.file=: 输出到文件的日志格式, 只有logback有效
  • logging.pattern.level=: 日志级别的格式, 默认是%5p. 只有logback有效
  • logging.exception-conversion-word=%wEx: log异常时使用哪个格式转换器(base.xml中定义了三个conversionRule)
  • logging.register-shutdown-hook=false # Register a shutdown hook for the logging system when it is initialized(没用过)

上面这些属性配置, 一般写在application.properties中, 这样会被加载到Spring Environment中, 为了方便其他地方使用, Spring Environment中的一些属性也被转换到了系统属性(System property)里, 下面是这些属性于系统属性的对应关系:

Spring Environment

System Property

logging.exception-conversion-word

LOG_EXCEPTION_CONVERSION_WORD

logging.file

LOG_FILE

logging.path

LOG_PATH

logging.pattern.console

CONSOLE_LOG_PATTERN

logging.pattern.file

FILE_LOG_PATTERN

logging.pattern.level

LOG_LEVEL_PATTERN

PID

PID

日志配置文件

logging.config属性用于指定日志配置文件的位置, 以logback为例.

  • 如果不指定该属性, logback本身会默认寻找classpath下的配置文件, 寻找顺序为: logback.groovy > logback-test.xml > logback.xml;
  • Spring Boot又加了俩默认的配置文件:logback-spring.groovy > logback-spring.xml, 这俩优先级低于上面的那三个. 推荐指定使用logback-spring.xml.
  • 不指定配置文件时, 寻找上面的配置文件, 制定了则加载指定的配置文件. 如:logging.config=classpath:logback-abc.xml, 则会加载classpath下的logback-abc.xml文件

使用groovy需要添加groovy的包依赖:

<dependency>

    <groupId>org.codehaus.groovy</groupId>

    <artifactId>groovy</artifactId>

    <version>2.4.7</version>

</dependency>

输出到日志文件

logging.filelogging.path这俩属性用于指定日志文件输出的位置. 默认情况下Spring Boot只会把日志输出到console, 添加了这两个属性(任意一个即可), 才会把日志输出到文件里.

  • 两个属性都不指定, 只输出到控制台, 不输出到文件
  • logging.file指定文件, 可以是相对路径, 可以是绝对路径.
  • logging.path指定目录, 若制定了目录, 则会输出日志到指定目录下的spring.log文件中
  • 两个同时指定, 以logging.file为准

spring-boot包里关于logback的配置file-appender.xml中定义了文件输出到${LOG_FILE}, 在同一包下的base.xml文件里有这么一句:<property name=”LOG_FILE” value=”${LOG_FILE:-${LOG_PATH:-${LOG_TEMP:-${java.io.tmpdir:-/tmp}}}/spring.log}”/>. 稍微分析下就知道为什么以logging.file为主, 指定logging.path时会输出到该目录下的spring.log文件里了.

注意上面语句中多次嵌套使用了${key:-defaultVlaue}形式

日志级别

logging.level.*用于指定日志级别, 比如:

logging.level.root=WARN

logging.level.org.springframework.web=DEBUG

logging.level.org.hibernate=ERROR

注意: 该属性配置的日志级别优先级要高于日志配置文件(如logback.xml), 即日志配置文件中与该属性定义的日志级别不一致时, 以该属性定义的级别为准.

日志格式

  • ogging.pattern.console指定在控制台输出的日志格式;
  • ogging.pattern.file指定在文件输出的日志格式;
  • ogging.pattern.level指定日之级别(DEBUG, INFO, ERROR等)的格式, 默认为%5p;

这些属性不指定时, 默认的格式在spring-boot包中的DefaultLogbackConfiguration类里有定义, 在defaults.xml里也有定义

格式大致为:

2016-11-02 21:59:11.366 INFO 11969 — [ main] o.apache.catalina.core.StandardService : Starting service Tomcat

依次为: 时间 日志级别 PID — [线程名] 日志名 : 日志内容

如何写自己的日志配置文件

spring-boot包里有四个相关的xml文件:

  • console-appender.xml: 定义了控制台输出的日志格式
  • file-appender.xml: 定义了一个日志的文件输出格式(指定每个文件10M)
  • defaults.xml: 定义了一些日志级别
  • base.xml: 包含了上面3个文件, 并指定了root的输出级别和输出方式

我们的日志配置线上不需要输出到console, 日志文件的大小一般也不会是10M, 所以上面那几个文件, 我们可以参考.

比如我们可以这样定义logback.xml

<?xml version=”1.0″ encoding=”UTF-8″?>

<configuration>

    <!– 这里面定义了 CONSOLE_LOG_PATTERN, FILE_LOG_PATTERN 等日志格式, 还定义了一些日志级别 –>

    <include resource=“org/springframework/boot/logging/logback/defaults.xml”/>

    <!– 命令行输出, 一般线上不用 –>

    <appender name=“CONSOLE” class=“ch.qos.logback.core.ConsoleAppender”>

        <encoder  charset=“UTF-8”>

            <pattern>${CONSOLE_LOG_PATTERN}</pattern>

        </encoder>

    </appender>

    <property name=“LOG_FILE_NAME” value=“myLog”/> <!– 定义一个属性, 下面用 –>

    <!– 输出格式 appender –>

    <appender name=“FILE” class=“ch.qos.logback.core.rolling.RollingFileAppender”>

        <file>${catalina.base}/logs/${LOG_FILE_NAME}.log</file>  <!– 可自己定义 –>

        <encoder>

            <pattern>${FILE_LOG_PATTERN}</pattern> <!– 输出格式也可自己定义 –>

        </encoder>

        <rollingPolicy class=“ch.qos.logback.core.rolling.TimeBasedRollingPolicy”>

            <fileNamePattern>${catalina.base}/logs/${LOG_FILE_NAME}.%d{yyyy-MM-dd}.log</fileNamePattern>

        </rollingPolicy>

    </appender>

    <!– error 日志 appender –>

    <appender name=“ERROR_FILE” class=“ch.qos.logback.core.rolling.RollingFileAppender”>

        <file>${catalina.base}/logs/${LOG_FILE_NAME}_error.log</file>

        <filter class=“ch.qos.logback.classic.filter.ThresholdFilter”>

            <level>ERROR</level>

        </filter>

        <encoder  charset=“UTF-8”>

            <pattern>${FILE_LOG_PATTERN}</pattern>

        </encoder>

        <rollingPolicy class=“ch.qos.logback.core.rolling.TimeBasedRollingPolicy”>

            <fileNamePattern>${catalina.base}/logs/${LOG_FILE_NAME}_error.%d{yyyy-MM-dd}.log</fileNamePattern>

        </rollingPolicy>

    </appender>

    <!– 定义日志级别, 也可在应用配置中指定 –>

    <logger name =“com.example.project” level=“INFO” />

    <logger name=“org.springframework.web” level=“DEBUG”/>

    <root level=“ERROR”>

        <appender-ref ref=“CONSOLE” /> <!– 线上不需要输出到 CONSOLE –>

        <appender-ref ref=“FILE” />

        <appender-ref ref=“ERROR_FILE” />

    </root>

</configuration>

  • 上例中, 日志会输出到文件XXX.log, 错误日志单独输出到一个XXX_error.log文件, 日志文件并每天打包一次.
  • 上例中, 应用配置(application.properties)里用于指定日志文件名文件位置的属性(logging.filelogging.path)将不起作用, 因为例子里没有用到这些属性, 其他配置(比如日志级别)仍有作用.
  • 上例中的哪个${catalina.base}算是一个系统变量, 表示应用所在目录, 文件名(位置)完全可以自己指定, 也可参考spring-boot包里的使用方式.

FROM HERE

Spring componentscan custom annotation

Everyone seems to think annotations are cool and want to use them now days. A lot has been written about the pros and cons of using annotations and personally I think they should be used with caution. Mixing annotation domains to a point of total confusion, spreading configuration related meta-data across large code bases to a point where refactoring becomes very hard are only some of the risks. Nevertheless, annotations are cool.

I wanted to add annotation functionality to some “aspect” of our code base. An aspect being an interface Foo and multiple implementations of Foo in various artifacts (e.g., FooA from project A, FooB from project B and so on).

1
2
3
public interface Foo{
  void bar();
}
1
2
3
4
5
6
public class FooA implements Foo{
  @Override
  public void bar(){
    System.out.println("I am number 6!");
  }
}

First thing I created a Fooish type-level (class-level) annotation

1
2
3
4
5
6
7
8
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Fooish {
  boolean cool() default true;
  String[] tags() default { "all" };
}

Next I annotated my classes with my new Fooish annotation:

1
2
3
4
5
6
7
@Fooish(cool=false, tags= {"sixfoo"})
public class FooA implements Foo{
  @Override
  public void bar(){
    System.out.println("I am number 6!");
  }
}

Meanwhile, in another Foo across the galaxy from A:

1
2
3
4
5
6
7
@Fooish(cool=true, tags= {"freefoo"})
public class FooB implements Foo{
  @Override
  public void bar(){
    System.out.println("I am not a number, I am a free man!");
  }
}

I am now ready to do some classpath scanning for my Foos. At first I went a looked the reflections library which I have to say is quite cool.

I popped the maven repository and dependencies:

1
2
3
4
5
<repository>
    <id>reflections-repo</id>
    <name>Reflections Maven2 Repository</name>
</repository>
01
02
03
04
05
06
07
08
09
10
<dependency>
  <groupId>org.reflections</groupId>
  <artifactId>reflections</artifactId>
  <version>0.9.5</version>
</dependency>
<dependency>
  <groupId>com.google.collections</groupId>
  <artifactId>google-collections</artifactId>
  <version>1.0</version>
</dependency>

And now I am ready to start scanning for annotations:

01
02
03
04
05
06
07
08
09
10
11
12
final StopWatch sw = new StopWatch();
sw.start();
final Reflections reflections = new Reflections("org.projectx", new TypeAnnotationsScanner());
Set<Class<?>> theFoos = reflections.getTypesAnnotatedWith(Fooish.class);
sw.stop();
System.out.println("Classpath scanning took: " + sw.getTime() + "ms");
for (final Class<?> theFoo : theFoos) {
final Fooish annotation = theFoo.getAnnotation(Fooish.class);
  if (Arrays.asList(annotation.tags()).contains("freefoo")) {
     System.out.println("This foo "+ theFoo.getClass().getName() + ", is a free foo");
  }
}

The reflections API has much more than is shown here, the output of the scan showed:

1
Classpath scanning took: 1782ms

Not bad for quite a large code base, but still, incurring a 2 seconds penalty for service load time is severe a production environment where services might be candidate to frequent restarts. Continuous deployment requires it to be snappy. A side note here, you should never try to do this kind of scanning during runtime, only load time. Reflection-based operations are costly in Java.

Next I suddenly remembered that Spring does this kind of work when you do stuff like <mvc:annotation-driven /> and <context:component-scan /> in you bean configuration file. There’s gotta be a way to hook up into that process use it for my own good. Turns out there is.

Spring allows you to load your annotated classes into their container if you also annotate them with the @Component type-level annotation. So my Foos need another annotation:

1
2
3
4
5
6
7
8
@Fooish(cool=true, tags= {"freefoo"})
@Component
public class FooB implements Foo{
  @Override
  public void bar(){
    System.out.println("I am not a number, I am a free man!");
  }
}

To load all my Foos into the Spring application context I added the following to my Spring configuration file:

1
2
3
<context:component-scan base-package="org.projectx">
  <context:include-filter type="annotation" expression="com.projectX.annotation.Fooish" />
</context:component-scan>

You can have other component scanners in the Spring configuration but this one is dedicated only to the classes annotated with @Component and @Fooish.

Now I want a Fooish handler which handles all instances of Fooish beans loaded to the context, I can easily do it with by implementing the ApplicationContextAware interface, then calling the getBeansWithAnnotation method of the ApplicationContext.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
public class MyFooishHandler implements ApplicationContextAware, InitializingBean {
  private ApplicationContext applicationContext;
  @Override
  public void afterPropertiesSet() throws Exception {
    final Map<String, Object> myFoos = applicationContext.getBeansWithAnnotation(Fooish.class);
    for (final Object myFoo : myFoos.values()) {
      final Class<? extends Object> fooClass = myFoo.getClass();
      final Fooish annotation = fooClass.getAnnotation(Fooish.class);
      System.out.println("Found foo class: " + fooClass + ", with tags: " + annotation.tags());
    }
  }
  @Override
  public void setApplicationContext(final ApplicationContext applicationContext)
      throws BeansException {
    this.applicationContext = applicationContext;
  }
}

I am sure there’s some overhead here to but the up side is once I annotate my Foos with @Component I can also take advantage of other features of the Spring container and this method doesn’t require additional dependencies on the classpath assuming Spring’s already there.

From here

The above article was written in 2010 and now if we need to use java config rather than the xml base config. Here is an example with exclude filter which also apply to the include filter we use above. Other than annotation, The FilterType could also be Regex/AspectJ/Custom etc.. according to the spring doc.

And here is a good discussion on design patterns used in Web app

spring annotation inheritance

@Autowired/@Inject (method)

When you use @Inherited on a class annotation, this means that when that annotation is queried on a non-annotated subclass, the Java will look for it in the superclass.

When you use @Inherited on a method annotation, this means that when that annotation is queried on a non-annotated method overridden in subclass, Java will look for it in the superclass.

If your setter method is annotated with @Autowired on the superclass, but the setter method is not overridden in subclass (which is usually the case), the annotation does not need to be @Inherited to be found when you look for annotated methods into the subclass.

Spring looks for all annotated setter methods in the class hierarchy. If a setter is annotated with @Autowired in the superclass and is overridden in the subclass without the @Autowired annotation, then Spring will not detect it and will not inject the dependency.

Code:
class A {
  @Autowired setFirst(First f) {}
  @Autowired setSecond(Second s) {}
}

class B extends A {
  @Overrides setFirst(First f) {}
}

In a bean definition declared as A, both setFirst() and setSecond() will be invoked, while in a bean definition declared as B, only setSecond() will be invoked, because setFirst() is overridden without @Autowired.
This behaviour is not spring-related, but java-related.

@Transactional(class/method)

the @Transactionalannotation has @Inherited.

From the docs:

Indicates that an annotation type is automatically inherited. If an Inherited meta-annotation is present on an annotation type declaration, and the user queries the annotation type on a class declaration, and the class declaration has no annotation for this type, then the class’s superclass will automatically be queried for the annotation type. This process will be repeated until an annotation for this type is found, or the top of the class hierarchy (Object) is reached. If no superclass has an annotation for this type, then the query will indicate that the class in question has no such annotation.

Note that this meta-annotation type has no effect if the annotated type is used to annotate anything other than a class. Note also that this meta-annotation only causes annotations to be inherited from superclasses; annotations on implemented interfaces have no effect.

Docs of @Transactional:

@Target(value={METHOD,TYPE})
@Retention(value=RUNTIME)
@Inherited
@Documented
public @interface Transactional

hibernate entitymanager spring BeanDefinitionStoreException FactoryConfigurationError DocumentBuilderFactory cannot be found

When we try to upgrade spring jpa/hibernate from 3 to 4. One of our standalone jar using spring has error when loading application context:

org.springframework.beans.factory.BeanDefinitionStoreException: Unexpected exception parsing XML document from ServletContext resource [/WEB-INF/spring/application-context-xxx.xml]; nested exception is javax.xml.parsers.FactoryConfigurationError: Provider for javax.xml.parsers.DocumentBuilderFactory cannot be found

 

After searching around, it turns out the hibernate-entitymanager 4.3.11 has a dependency on jdom which has a dependency on xml-apis which will conflict with the JRE’s rt.jar’s javax.xml stuff. We exclude it so that our spring xml config could be correctly parsed.

To solve the problem, we can just exclude the xml-apis from the dependency tree.

        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-entitymanager</artifactId>
            <exclusions>
                <!--the hibernate-entitymanager 4.3 has a dependency on jdom which has a dependency on xml-apis which will conflict with
                    the JRE's rt.jar's javax.xml stuff. We exclude it so that our spring xml config could be correctly parsed.-->
                <exclusion>
                    <groupId>xml-apis</groupId>
                    <artifactId>xml-apis</artifactId>
                </exclusion>
            </exclusions>
        </dependency>