适配器模式

适配器模式能使接口不兼容的对象相互合作。适配器是一个特殊的对象,能够转换对象接口,使其能与其他对象进行交互。它的运作方式是,新建一个适配器,实现与其中一个现有对象兼容的接口,现有对象可以使用该接口安全地调用适配器方法,适配器方法被调用后将以另一个对象兼容的格式和顺序将请求传递给该对象。

适配器模式一个典型的应用场景是统一数据格式和方法参数。下面以 Spring 中的 ApplicationListener 接口为例,介绍适配器模式。

Spring 框架中,ApplicationListener 用于监听事件,执行相应的处理逻辑。其接口定义如下:

@FunctionalInterface
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
    void onApplicationEvent(E var1);
}

有两种方式可以实现事件监听,分别是使用接口和注解。

  • 接口方式
@Component
public class UserLoginEventListener implements ApplicationListener<UserLoginEvent> {

    @Override
    public void onApplicationEvent(UserLoginEvent event) {
        System.out.println("用户已经登录: " + event.getUserName());
    }
}
  • 注解方式
@Component
public class UserLoginEventListener {

    @EventListener
    public void myEventListenerMethod(UserLoginEvent event) {
        System.out.println("用户已经登录: " + event.getUserName());
    }
}

但是不管使用哪种方式,Spring 最终都只会调用 ApplicationListener 对象的 onApplicationEvent 方法来触发监听。在 Spring 的源码中,@EventListener 注解所修饰的方法最终会被封装成一个 ApplicationListenerMethodAdapter 对象,在其 onApplicationEvent 方法中通过反射调用对应的方法。源码如下:

public class DefaultEventListenerFactory implements EventListenerFactory, Ordered {
    
    // 省略其他代码

    /**
     * beanName @EventListener 注解所在 bean 的名称
     * type @EventListener 注解所在 bean 的类型
     * method 被 @EventListener 注解修饰的方法
     */
	@Override
	public ApplicationListener<?> createApplicationListener(String beanName, Class<?> type, Method method) {
		return new ApplicationListenerMethodAdapter(beanName, type, method);
	}
}
/**
 * 实现 ApplicationListener 接口
 */
public class ApplicationListenerMethodAdapter implements GenericApplicationListener {

	protected final Log logger = LogFactory.getLog(getClass());

	private final String beanName;

	private final Method method;

	private final Method targetMethod;

	private final AnnotatedElementKey methodKey;

	@Nullable
	private ApplicationContext applicationContext;

	@Nullable
	private EventExpressionEvaluator evaluator;

    /**
     * 构造方法
     */
	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);
	}

    /**
     * 监听方法
     */ 
	@Override
	public void onApplicationEvent(ApplicationEvent event) {
		processEvent(event);
	}

	/**
	 * 通过反射调用监听方法
	 */
	public void processEvent(ApplicationEvent event) {
		Object[] args = resolveArguments(event);
		if (shouldHandle(event, args)) {
            // 通过反射调用监听方法
			Object result = doInvoke(args);
			if (result != null) {
				handleResult(result);
			}
			else {
				logger.trace("No result object given - no result to handle");
			}
		}
	}

    @Nullable
	protected Object doInvoke(Object... args) {
		Object bean = getTargetBean();
		// Detect package-protected NullBean instance through equals(null) check
		if (bean.equals(null)) {
			return null;
		}

		ReflectionUtils.makeAccessible(this.method);
		try {
			return this.method.invoke(bean, args);
		}
    }

    /**
     * 从 IOC 容器中获取 bean
     */
    protected Object getTargetBean() {
		Assert.notNull(this.applicationContext, "ApplicationContext must no be null");
		return this.applicationContext.getBean(this.beanName);
	}
}