为什么在Spring AOP中,对象被包装到实现接口的JDK代理中?

时间:2015-04-15 12:33:42

标签: java spring design-patterns aop spring-aop

我正在学习Spring,我有以下内容

考虑以下bean定义:

<bean id="clientService" class="com.myapp.service.ClientServiceImpl" />

现在考虑一下它被声明为切入点*的情况,目标是** clientService bean中的所有方法。

还要考虑 ClientServiceImpl 实现3个接口

现在我知道使用 AOP 代理了 clientService bean,并且该代理实现了所有3个接口。

但实现所有这3个接口的确切原因是什么?

所以在我看来存在两种代理(如果我说的是错误的断言,请纠正我):

  1. JDK代理:默认使用Spring(是真的吗?),我有一个界面来定义我想要代理的对象的方法。所以这个接口的具体实现是由代理包装的。所以当我在我的对象上调用一个方法时,我在它的代理上调用它。该调用由方法拦截器识别,最终执行该方面,然后执行调用的方法。

  2. CGLIB代理:在我看来,代理扩展了包装对象的实现,为其添加了额外的逻辑功能

  3. 这样的事情:

    enter image description here

    所以在我看来,Spring使用第一种基于接口实现的代理(是不是?):

    enter image description here

    我认为在 AOP 中,额外的逻辑由方法拦截器的实现来表示(是真的吗?)并且标准逻辑由实现表示定义在接口中的方法。

    但是,如果之前的推理是正确的,我的疑问是:为什么我需要定义这些接口并执行这个对象包装的对象实现这些接口? (我无法理解代理本身是否实现了这些接口)。

    为什么呢?究竟是如何运作的?

    Tnx

1 个答案:

答案 0 :(得分:3)

  

但是这三个界面的确切原因是什么   执行吗?

如果代理没有实现所有这些接口,则bean无法连接到使用该接口的其他bean(您将获得ClassCastException)。例如,将该接口的所有bean自动装配到bean中。此外,如果代理没有实现界面,getBeanNamesForType之类的内容也无法使用。

  

所以在我看来,存在两种代理(如果我是正确的我   说错误的断言)

是的,这是对的。见ScopedProxyMode。默认情况下,Spring不会创建代理。如果需要包装bean以添加其他行为(AOP),它只会创建一个代理。请注意,还有a special case of the CGLIB based proxy使用Objenesis来处理没有默认构造函数的子类化目标。

  

CGLIB代理:在我看来,代理扩展了   包装对象的实现为其添加了额外的逻辑   特征

当你使用基于CGLIB的代理时,bean的构造函数会被调用两次:一次是动态生成的子类被实例化(创建代理),第二次是创建实际的bean(目标)。

  

我认为在AOP中,额外的逻辑由...表示   方法拦截器的实现(是真的吗?)

代理基本上只是调用需要应用的建议链。该建议未在代理本身中实施。例如,@Transactional的建议位于TransactionAspectSupport。看一下JdkDynamicAopProxy的来源。

  

和标准逻辑由执行表示   定义在接口中的方法。

假设您正在针对接口进行编程并使用正确的JDK代理。

  

但是,如果先前的推理是正确的,我的怀疑是:为什么我需要   定义这些接口并执行该对象包装的对象   实现这些接口? (我无法理解代理本身   实现这些接口)。

如果要使用基于接口的代理,则需要使用接口。只需确保所有bean都实现接口,所有建议的方法都由这些接口定义,并且当一个bean依赖于另一个bean时,使用接口指定该依赖项。 Spring将负责构建代理并确保它实现所有接口。

在你的图表中,你有&#34; Spring AOP Proxy(this)&#34;。当您使用任何类型的代理时,必须非常小心使用this

  1. 同一班级内的通话不会申请通知,因为这些通话不会通过代理。
  2. 如果您在其中一个bean中将this传递给某些外部代码,那么您将通过AOP建议的目标。如果其他一些代码使用该引用,则呼叫不会应用AOP建议(再次,您绕过代理)。