第7章-AOP的执行流程原理和监听器原理

流程图-AOP运行流程原理

由Aop的执行流程引出方法拦截器

创建完代理对象之后,怎么执行的呢?

断点打到这里,F7进入方法

自然而然的跳到了cglib这里

CglibAopProxy#intercept()

public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
Object target = null;
TargetSource targetSource = this.advised.getTargetSource();
try {
if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// Get as late as possible to minimize the time we "own" the target, in case it comes from a pool...
target = targetSource.getTarget();
Class<?> targetClass = (target != null ? target.getClass() : null);
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
Object retVal;
// Check whether we only have one InvokerInterceptor: that is,
// no real advice, but just reflective invocation of the target.
if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = methodProxy.invoke(target, argsToUse);
}
else {
// We need to create a method invocation...
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
}
retVal = processReturnType(proxy, target, method, retVal);
return retVal;
}
finally {
if (target != null && !targetSource.isStatic()) {
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}

CglibAopProxy#getInterceptorsAndDynamicInterceptionAdvice()

  1. 把5个增强器变成了方法拦截器,增强器只是保存信息的,真正执行还得靠方法拦截器。
  2. 我们再给上面的470行打上断点,看下之前是如何生成方法拦截器的。因为第一次生成的时候没有缓存,肯定能进去470行。

如何生成的方法拦截器?

Debug调用栈

可以看到就是在之前创建代理对象的时候增强器转成的拦截器

DefaultAdvisorChainFactory#getInterceptorsAndDynamicInterceptionAdvice()开始将增强器转为方法拦截器

public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
Advised config, Method method, @Nullable Class<?> targetClass) {

// This is somewhat tricky... We have to process introductions first,
// but we need to preserve order in the ultimate list.
AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
Advisor[] advisors = config.getAdvisors();
List<Object> interceptorList = new ArrayList<>(advisors.length);
Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
Boolean hasIntroductions = null;

for (Advisor advisor : advisors) {
if (advisor instanceof PointcutAdvisor) {
// Add it conditionally.
PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
boolean match;
if (mm instanceof IntroductionAwareMethodMatcher) {
if (hasIntroductions == null) {
hasIntroductions = hasMatchingIntroductions(advisors, actualClass);
}
match = ((IntroductionAwareMethodMatcher) mm).matches(method, actualClass, hasIntroductions);
}
else {
match = mm.matches(method, actualClass);
}
if (match) {
MethodInterceptor[] interceptors = registry.getInterceptors(advisor);//(如果是通知方法)把增强器转拦截器
if (mm.isRuntime()) {
// Creating a new object instance in the getInterceptors() method
// isn't a problem as we normally cache created chains.
for (MethodInterceptor interceptor : interceptors) {
interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
}
}
else {
interceptorList.addAll(Arrays.asList(interceptors));
}
}
}
}
else if (advisor instanceof IntroductionAdvisor) {
IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
else {
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}

return interceptorList; //所有增强器转好拦截器
}

DefaultAdvisorAdapterRegistry#getInterceptors()

   private final List<AdvisorAdapter> adapters = new ArrayList<>(3);

public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
List<MethodInterceptor> interceptors = new ArrayList<>(3);
Advice advice = advisor.getAdvice();
if (advice instanceof MethodInterceptor) {
interceptors.add((MethodInterceptor) advice);
}
for (AdvisorAdapter adapter : this.adapters) {
if (adapter.supportsAdvice(advice)) { //这里应该是一个适配器模式
interceptors.add(adapter.getInterceptor(advisor));
}
}
if (interceptors.isEmpty()) {
throw new UnknownAdviceTypeException(advisor.getAdvice());
}
return interceptors.toArray(new MethodInterceptor[0]);
}
  1. 增强器只是保存了哪些方法是通知方法的详细信息
  2. 拦截器里写了反射执行通知方法的逻辑,具体执行还得要方法拦截器

MethodBeforeAdviceAdapter适配器模式将增强器适配成方法拦截器

适配器模式适配一下

class MethodBeforeAdviceAdapter implements AdvisorAdapter, Serializable {

@Override
public boolean supportsAdvice(Advice advice) {
return (advice instanceof MethodBeforeAdvice);
}

@Override
public MethodInterceptor getInterceptor(Advisor advisor) {
MethodBeforeAdvice advice = (MethodBeforeAdvice) advisor.getAdvice();
return new MethodBeforeAdviceInterceptor(advice);
}

}

MethodBeforeAdviceInterceptor

public class MethodBeforeAdviceInterceptor implements MethodInterceptor, BeforeAdvice, Serializable {

private final MethodBeforeAdvice advice;


/**
* Create a new MethodBeforeAdviceInterceptor for the given advice.
* @param advice the MethodBeforeAdvice to wrap
*/
public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) {
Assert.notNull(advice, "Advice must not be null");
this.advice = advice;
}


@Override
@Nullable
public Object invoke(MethodInvocation mi) throws Throwable { //invoke真正执行
this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
return mi.proceed();
}

}

然后debug回到accept()方法

正式开始分析AOP运行流程-链式执行

  1. F7进入方法,上面讲过会调用CglibAopProxy内部类的DynamicAdvisedInterceptor#intercept()。这次我们来说下为什么会跳到DynamicAdvisedInterceptor#intercept()方法
  2. HelloService是一个代理对象,它的AOP代理是一个DynamicAdvisedInterceptor对象
  1. 而DynamicAdvisedInterceptor实现了MethodInterceptor接口
private static class DynamicAdvisedInterceptor implements MethodInterceptor, Serializable{...}
  1. cglib代理就是,当你调用方法的时候,真正会调用到实现了MethodInterceptor接口的DynamicAdvisedInterceptor#intercept()
  2. 至于具体的cglib原理,可以自己百度下。下面就看看intercept()的逻辑

注意有两个MethodInterceptor,包名不一样

package org.springframework.cglib.proxy;

import java.lang.reflect.Method;

public interface MethodInterceptor extends Callback {
Object intercept(Object var1, Method var2, Object[] var3, MethodProxy var4) throws Throwable;
}
package org.aopalliance.intercept; //Spring定义的AOP规范接口

import javax.annotation.Nonnull;
import javax.annotation.Nullable;

@FunctionalInterface
public interface MethodInterceptor extends Interceptor {

@Nullable
Object invoke(@Nonnull MethodInvocation invocation) throws Throwable;

}

DynamicAdvisedInterceptor#intercept()

有intercept的是cglib的MethodInterceptor接口

@Nullable //回调方法
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
Object target = null;
// 这里面有最原生的HelloService对象
TargetSource targetSource = this.advised.getTargetSource();
try { //使用了代理对象就有增强功能
if (this.advised.exposeProxy) { //使用ThreadLocal线程共享这个代理对象;
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// Get as late as possible to minimize the time we "own" the target, in case it comes from a pool...
target = targetSource.getTarget();
Class<?> targetClass = (target != null ? target.getClass() : null);
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
Object retVal; //chain是AOP后置处理器在第一次的时候就生成好的5个增强器,然后封装成的MethodInterceptor
// Check whether we only have one InvokerInterceptor: that is,
// no real advice, but just reflective invocation of the target.
if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
// We can skip creating a MethodInvocation: just invoke the target directly.
// Note that the final invoker must be an InvokerInterceptor, so we know
// it does nothing but a reflective operation on the target, and no hot
// swapping or fancy proxying.
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = methodProxy.invoke(target, argsToUse);
}
else { //CglibMethodInvocation【FilterChain(维护索引)】,5个MethodInterceptor就是Filter
//创建一个方法执行的东西(拦截器链在此执行) We need to create a method invocation...
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
}
retVal = processReturnType(proxy, target, method, retVal);
return retVal;
}
finally {
if (target != null && !targetSource.isStatic()) {
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}

在前面创建HelloService代理对象时创建好的方法拦截器,然后调用proceed()

CglibMethodInvocation#proceed()

顾名思义,就是用来执行Cglib生成的代理对象的方法

CglibAopProxy#proceed()

public Object proceed() throws Throwable {
try {
return super.proceed(); //调用父类的方法
}
catch (RuntimeException ex) {
throw ex;
}
catch (Exception ex) {
if (ReflectionUtils.declaresException(getMethod(), ex.getClass()) ||
KotlinDetector.isKotlinType(getMethod().getDeclaringClass())) {
// Propagate original exception if declared on the target method
// (with callers expecting it). Always propagate it for Kotlin code
// since checked exceptions do not have to be explicitly declared there.
throw ex;
}
else {
// Checked exception thrown in the interceptor but not declared on the
// target method signature -> apply an UndeclaredThrowableException,
// aligned with standard JDK dynamic proxy behavior.
throw new UndeclaredThrowableException(ex);
}
}
}

ReflectiveMethodInvocation#proceed()

public Object proceed() throws Throwable {
// 当前拦截器的索引有没有超过 拦截器总数量-1 We start with an index of -1 and increment early.
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}

Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
// Evaluate dynamic method matcher here: static part will already have
// been evaluated and found to match.
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
}
else {
// Dynamic matching failed.
// Skip this interceptor and invoke the next in the chain.
return proceed();
}
}
else {
// It's an interceptor, so we just invoke it: The pointcut will have
// been evaluated statically before this object was constructed.
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}

上面5个拦截器都继承了Spring的org.aopalliance.intercept.MethodInterceptor,和Cglib的MethodInterceptor没关系了

ExposeInvocationInterceptor第一个拦截器

获取第一个拦截器ExposeInvocationInterceptor

往下走,直接走到了这里,准备调用ExposeInvocationInterceptor的invoke()

CglibAopProxy#proceed()
public Object proceed() throws Throwable {
try {
return super.proceed(); //调用父类的方法
}
catch (RuntimeException ex) {
throw ex;
}
catch (Exception ex) {
if (ReflectionUtils.declaresException(getMethod(), ex.getClass()) ||
KotlinDetector.isKotlinType(getMethod().getDeclaringClass())) {
// Propagate original exception if declared on the target method
// (with callers expecting it). Always propagate it for Kotlin code
// since checked exceptions do not have to be explicitly declared there.
throw ex;
}
else {
// Checked exception thrown in the interceptor but not declared on the
// target method signature -> apply an UndeclaredThrowableException,
// aligned with standard JDK dynamic proxy behavior.
throw new UndeclaredThrowableException(ex);
}
}
}

结果又调回了,很明显这是个递归调用

MethodBeforeAdviceInterceptor-前置通知

然后后面的调用逻辑和前面就一样了,如下

这个时候就先执行切面的before方法,前置通知就执行了

继续调父类的方法

AspectJAfterAdvice-后置通知

后置通知这里先不执行,先继续执行下面的方法拦截器链路,最后finally再执行后置通知

AfterReturningAdviceInterceptor-返回通知

  1. 先往下走,我们就继续

AspectJAfterThrowingAdvice-异常通知

继续往下发现索引要超了

真正执行sayhello()

放行之后看控制台,sayhello方法就打印了。并且到目前为止,只有前面说的前置通知执行了。

然后咱们就往后返,

—返回—

AspectJAfterThrowingAdvice-异常通知

咱们这里没异常,就继续返回了

AfterReturningAdviceInterceptor-返回通知

返回到这里,准备执行返回通知

放行之后的控制台

继续返回

AspectJAfterAdvice-后置通知

准备执行后置通知

放行finally之后的控制台

ExposeInvocationInterceptor

继续返回

CglibAopProxy$DynamicAdvisedInterceptor

最后over,回到刚开头说的那个地方

Spring杂项

监听器原理【事件原理】

测试类

AppEventListener

@Component
public class AppEventListener {

public AppEventListener(){
System.out.println("AppEventListener...");
}

@EventListener(MessageEvent.class) //监听事件
public void listenMessage(MessageEvent event){
System.out.println("Message事件到达..."+event+";已发送邮件....");
}


@EventListener(ChangeEvent.class)
public void listenChange(ChangeEvent event){
System.out.println("Change事件到达..."+event+";已同步状态....");
}

@EventListener(PayloadApplicationEvent.class) //感知任意对象事件的
public void listenPayload(PayloadApplicationEvent<A> event){
System.out.println("Payload事件到达..."+event.getPayload()+";已进行处理....");
}

}

AppEventPublisher

@Component
public class AppEventPublisher implements ApplicationEventPublisherAware {

ApplicationEventPublisher eventPublisher;
public AppEventPublisher(){
System.out.println("AppEventPublisher....");
}

@Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.eventPublisher = applicationEventPublisher;
}

public void publish(ApplicationEvent applicationEvent){
eventPublisher.publishEvent(applicationEvent);
}

public void publish(Object o){
eventPublisher.publishEvent(o);
}
}

ChangeEvent

/**
* 事件需要实现序列化接口
*/
public class ChangeEvent extends ApplicationEvent implements Serializable {
private static final long serialVersionUID = 0L;
private String state;
private ChangeEvent(Object source) {
super(source);
}

public ChangeEvent(Object source,String state){
super(source);
this.state = state;
}

public String getState() {
return state;
}

@Override
public String toString() {
return "ChangeEvent{" +
"state='" + state + '\'' +
", source=" + source +
'}';
}
}

MessageEvent

/**
* 事件需要实现序列化接口
*/
public class MessageEvent extends ApplicationEvent implements Serializable {
private static final long serialVersionUID = 0L;

public MessageEvent(String source) {
super(source);
}

@Override
public String toString() {
return "MessageEvent{" +
", source=" + source +
'}';
}
}

AnnotationMainTest

package cn.imlql.spring;

/**
* 注解版Spring的用法
*/
public class AnnotationMainTest {

public static void main(String[] args) {

ApplicationContext applicationContext =
new AnnotationConfigApplicationContext(MainConfig.class);


// 下面两种使用方法都可以
// applicationContext.publishEvent(new Object());
// applicationContext.publishEvent(new ApplicationEvent() {
// @Override
// public String toString() {
// return super.toString();
// }
// });

//测试事件
AppEventPublisher eventPublisher = applicationContext.getBean(AppEventPublisher.class);
eventPublisher.publish(new A());
eventPublisher.publish(new MessageEvent("hello,你好"));
eventPublisher.publish(new ChangeEvent(eventPublisher,"sending..."));
}
}

在还未进行refresh()十二大步刷新时,容器就已经有了这两事件相关的Bean定义信息了。

EventListenerMethodProcessor

继承树

  1. 我们看到实现了SmartInitializingSingleton和BeanFactoryPostProcessor
  2. BeanFactoryPostProcessor我们反复在说,就是工厂后置处理环节。EventListenerMethodProcessor实现了BeanFactoryPostProcessor,说明他在工厂后置处理环节会做事
  3. SmartInitializingSingleton我们虽然说的不多,但也说过几次,调用链路如下。说明它会在容器刷新12大步的最后一步做事,并且看代码位置是在所有Bean创建完成之后做事。

AbstractApplicationContext#refresh() ==> AbstractApplicationContext#finishBeanFactoryInitialization() ==> DefaultListableBeanFactory#preInstantiateSingletons()

怎么分析呢?还是老办法,给EventListenerMethodProcessor标注@Override的方法打上断点

Debug启动

果然是从工厂后置处理那里过来的

放行,继续往下走。果然SmartInitializingSingleton这里开始做事了

EventListenerMethodProcessor#afterSingletonsInstantiated()

public void afterSingletonsInstantiated() {
ConfigurableListableBeanFactory beanFactory = this.beanFactory;
Assert.state(this.beanFactory != null, "No ConfigurableListableBeanFactory set");
String[] beanNames = beanFactory.getBeanNamesForType(Object.class);
for (String beanName : beanNames) {
if (!ScopedProxyUtils.isScopedTarget(beanName)) {
Class<?> type = null;
try {
type = AutoProxyUtils.determineTargetClass(beanFactory, beanName);
}
catch (Throwable ex) {
// An unresolvable bean type, probably from a lazy bean - let's ignore it.
if (logger.isDebugEnabled()) {
logger.debug("Could not resolve target class for bean with name '" + beanName + "'", ex);
}
}
if (type != null) {
if (ScopedObject.class.isAssignableFrom(type)) {
try {
Class<?> targetClass = AutoProxyUtils.determineTargetClass(
beanFactory, ScopedProxyUtils.getTargetBeanName(beanName));
if (targetClass != null) {
type = targetClass;
}
}
catch (Throwable ex) {
// An invalid scoped proxy arrangement - let's ignore it.
if (logger.isDebugEnabled()) {
logger.debug("Could not resolve target bean for scoped proxy '" + beanName + "'", ex);
}
}
}
try {
processBean(beanName, type); //主要是这里
}
catch (Throwable ex) {
throw new BeanInitializationException("Failed to process @EventListener " +
"annotation on bean with name '" + beanName + "'", ex);
}
}
}
}
}

我们在这里打上条件断点

F7进入下面的方法

咱们发现是创建了一个适配器

public ApplicationListenerMethodAdapter(String beanName, Class<?> targetClass, Method method) {
this.beanName = beanName;
this.method = BridgeMethodResolver.findBridgedMethod(method);
this.targetMethod = (!Proxy.isProxyClass(targetClass) ?
AopUtils.getMostSpecificMethod(method, targetClass) : this.method);
this.methodKey = new AnnotatedElementKey(this.targetMethod, targetClass);

EventListener ann = AnnotatedElementUtils.findMergedAnnotation(this.targetMethod, EventListener.class);
this.declaredEventTypes = resolveDeclaredEventTypes(method, ann);
this.condition = (ann != null ? ann.condition() : null);
this.order = resolveOrder(this.targetMethod);
}

为啥要创建这样一个适配器呢?虽然我们的AppEventListener不是监听器,它只是在方法里标注了监听注解,我们自己没有写监听器。但是咱们解析@EventListener注解之后,在这里生成的适配器却实现了EventListener,也就说明这个适配器就是个监听器。

继续往下放行

把适配器放到了事件多播器里

  1. 这个思想就是,咱们自己创建的AppEventListener不是监听器,只在方法里标了注解
  2. spring准备了另外一个类ApplicationListenerMethodAdapter,把你这个beanName和方法名等等信息封装到这里。然后放到事件多播器里
  3. 等以后真正的事件来了之后派发给ApplicationListenerMethodAdapter,ApplicationListenerMethodAdapter再用之前保存的信息反射调用实际的方法

最后就是三个方法,三个适配器

监听器如何感知到事件?

给下面的位置打上断点

AbstractApplicationContext#publishEvent()
public void publishEvent(Object event) {
publishEvent(event, null);
}


protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
Assert.notNull(event, "Event must not be null");

// Decorate event as an ApplicationEvent if necessary
ApplicationEvent applicationEvent;
if (event instanceof ApplicationEvent) { // ApplicationEvent接口下的事件
applicationEvent = (ApplicationEvent) event;
}
else { //任意对象作为事件最终被封装到了 PayloadApplicationEvent
applicationEvent = new PayloadApplicationEvent<>(this, event);
if (eventType == null) {
eventType = ((PayloadApplicationEvent<?>) applicationEvent).getResolvableType();
}
}

// Multicast right now if possible - or lazily once the multicaster is initialized
if (this.earlyApplicationEvents != null) {
this.earlyApplicationEvents.add(applicationEvent);
}
else { //拿到多播器发送事件即可
getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
}

// Publish event via parent context as well...
if (this.parent != null) {
if (this.parent instanceof AbstractApplicationContext) {
((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
}
else {
this.parent.publishEvent(event);
}
}
}
SimpleApplicationEventMulticaster#multicastEvent()
   //事件派发可以是异步
@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
Executor executor = getTaskExecutor();
for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
if (executor != null) { //使用观察者模式,把所有事件监听器拿来,调用他们的onApplicationEvent方法即可
executor.execute(() -> invokeListener(listener, event));
}
else {
invokeListener(listener, event);
}
}
}

protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
ErrorHandler errorHandler = getErrorHandler();
if (errorHandler != null) {
try {
doInvokeListener(listener, event);
}
catch (Throwable err) {
errorHandler.handleError(err);
}
}
else {
doInvokeListener(listener, event);
}
}

@SuppressWarnings({"rawtypes", "unchecked"})
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
try {
listener.onApplicationEvent(event);//调用咱们实现的方法
}
catch (ClassCastException ex) {
String msg = ex.getMessage();
if (msg == null || matchesClassCastMessage(msg, event.getClass()) ||
(event instanceof PayloadApplicationEvent &&
matchesClassCastMessage(msg, ((PayloadApplicationEvent) event).getPayload().getClass()))) {
// Possibly a lambda-defined listener which we could not resolve the generic event type for
// -> let's suppress the exception.
Log loggerToUse = this.lazyLogger;
if (loggerToUse == null) {
loggerToUse = LogFactory.getLog(getClass());
this.lazyLogger = loggerToUse;
}
if (loggerToUse.isTraceEnabled()) {
loggerToUse.trace("Non-matching event type for listener: " + listener, ex);
}
}
else {
throw ex;
}
}
}