简体   繁体   English

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

[英]Why in Spring AOP the object are wrapped into a JDK proxy that implements interfaces?

I am studying Spring and I have the followig 我正在学习春天,我有跟随

Consider the following bean definition: 考虑以下bean定义:

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

Now consider the case on which it is declared a pointcut* targetting all methods inside the **clientService bean. 现在考虑一下它被声明为切入点*的情况,目标是** clientService bean中的所有方法

Consider also that the ClientServiceImpl class implements 3 interfaces 还要考虑ClientServiceImpl实现3个接口

Now I know that using AOP the clientService bean is proxied and that this proxy implements all the 3 interfaces. 现在我知道使用AOP 会对clientService bean进行代理,并且该代理实现所有3个接口。

But what is the exact reason for which all these 3 interface are implemented? 但是实现所有这三个接口的确切原因是什么?

So it seems to me that exist 2 kinds of proxies (correct me if I am saying wrong assertions): 所以在我看来,存在两种代理(如果我说的是错误的断言,请纠正我):

  1. JDK Proxy : used by default from Spring (is it true?) in wicht I have an interface that define the method of the object that I want to proxify. JDK代理 :默认使用Spring(是真的吗?),我有一个接口,用于定义我想要代理的对象的方法。 So the concrete implementation of this interface is wrapped by the proxy. 所以这个接口的具体实现是由代理包装的。 So when I call a method on my object I am calling it on its proxy. 所以当我在我的对象上调用一个方法时,我在它的代理上调用它。 The call is recognized by a method interceptor that eventually perform the aspect and then is performed the invoked method. 调用由最终执行方面的方法拦截器识别,然后执行调用的方法。

  2. CGLIB Proxy: in wich, it seems to me that, the proxy extend the implementation of the wrapped object adding to it the extra logic features CGLIB代理:在我看来,代理扩展了包装对象的实现,增加了额外的逻辑特性

Something like this: 像这样的东西:

在此输入图像描述

So it seems to me that Spring use the first kind of proxy that is based on the implementation of interfaces (is it right?): 所以在我看来Spring使用第一种基于接口实现的代理(是不是?):

在此输入图像描述

I think that in AOP the extra logic is represented by the implementation of the method interceptor (is it true?) and the standard logic is represented by the implementation of the method defined into the interfaces. 我认为在AOP中 ,额外的逻辑由方法拦截器的实现来表示(是真的吗?),标准逻辑由定义在接口中的方法的实现来表示。

But, if the previous reasoning are correct, my doubts is: why I need to define these interface and do that the object wrapped by the object implement these interfaces? 但是,如果之前的推理是正确的,我的疑问是:为什么我需要定义这些接口,并且由对象包装的对象实现这些接口? (I can't understand if the proxy itself implement these interfaces). (我无法理解代理本身是否实现了这些接口)。

Why? 为什么? How exactly works? 究竟如何运作?

Tnx TNX

But what is the exact reason for which all these 3 interface are implemented? 但是实现所有这三个接口的确切原因是什么?

If the proxy didn't implement all of those interfaces, the bean couldn't be wired into other beans that use that interface (you'd get a ClassCastException). 如果代理没有实现所有这些接口,则无法将bean连接到使用该接口的其他bean(您将获得ClassCastException)。 For example, autowiring all of the beans of that interface into a bean. 例如,将该接口的所有bean自动装配到bean中。 Additionally, things like getBeanNamesForType wouldn't work if the proxy didn't implement the interface. 此外,如果代理未实现接口,则getBeanNamesForType内容将无法工作。

So it seems to me that exist 2 kinds of proxies (correct me if I am saying wrong assertions) 所以在我看来,存在两种代理(如果我说的是错误的断言,请纠正我)

Yes that's correct. 对,那是正确的。 See ScopedProxyMode . 请参阅ScopedProxyMode By default, Spring won't create a proxy. 默认情况下,Spring不会创建代理。 It only creates a proxy if it needs to wrap the bean to add additional behavior (AOP). 如果需要包装bean以添加其他行为(AOP),它只会创建一个代理。 Note that there's also a special case of the CGLIB based proxy that uses Objenesis to deal with subclassing targets that don't have a default constructor. 请注意,还有一个基于CGLIB的代理的特例,它使用Objenesis来处理没有默认构造函数的子类化目标。

CGLIB Proxy: in wich, it seems to me that, the proxy extend the implementation of the wrapped object adding to it the extra logic features CGLIB代理:在我看来,代理扩展了包装对象的实现,增加了额外的逻辑特性

When you use CGLIB based proxies, the constructor for your bean gets called twice: once when the dynamically generated subclass is instantiated (to create the proxy) and a second time when the actual bean is created (the target). 当您使用基于CGLIB的代理时,bean的构造函数会被调用两次:一次是动态生成的子类实例化(创建代理),另一次是创建实际的bean(目标)。

I think that in AOP the extra logic is represented by the implementation of the method interceptor (is it true?) 我认为在AOP中,额外的逻辑由方法拦截器的实现来表示(是真的吗?)

The proxy is essentially just invoking the chain of advice needs to be applied. 代理基本上只是调用需要应用的建议链。 That advice isn't implemented in the proxy itself. 该建议未在代理本身中实现。 For example, the advice for @Transactional lives in TransactionAspectSupport . 例如,对@Transactional的建议存在于TransactionAspectSupport中 Take a look at the source to JdkDynamicAopProxy . 看一下JdkDynamicAopProxy的源代码

and the standard logic is represented by the implementation of the method defined into the interfaces. 标准逻辑由接口中定义的方法的实现表示。

Assuming that you're programming against interfaces and using JDK proxies that's correct. 假设您正在针对接口进行编程并使用正确的JDK代理。

But, if the previous reasoning are correct, my doubts is: why I need to define these interface and do that the object wrapped by the object implement these interfaces? 但是,如果之前的推理是正确的,我的疑问是:为什么我需要定义这些接口,并且由对象包装的对象实现这些接口? (I can't understand if the proxy itself implement these interfaces). (我无法理解代理本身是否实现了这些接口)。

If you want to use interface based proxies you need to use interfaces. 如果要使用基于接口的代理,则需要使用接口。 Just make sure all of your beans implement interfaces, all of your advised methods are defined by those interfaces, and that when one bean depends on another bean, that dependency is specified using an interface. 只需确保所有bean都实现接口,所有建议的方法都由这些接口定义,并且当一个bean依赖于另一个bean时,使用接口指定该依赖项。 Spring will take care of constructing the proxy and making sure it implements all of the interfaces. Spring将负责构建代理并确保它实现所有接口。

In your diagram, you have "Spring AOP Proxy (this)". 在您的图表中,您有“Spring AOP Proxy(this)”。 You have to be really careful with using this when you're using any type of proxying. 当您使用任何类型的代理时,您必须非常小心地使用this

  1. Calls within the same class won't have advice applied because those calls won't pass through the proxy. 同一类中的调用将不会应用建议,因为这些调用不会通过代理。
  2. If in one of your beans you pass this to some outside code, you're passing the target of the AOP advice. 如果你的bean中的一个你通过this一些外部的代码,你传递了AOP通知的目标。 If some other code uses that reference, the calls won't have AOP advice applied (again, you're bypassing the proxy). 如果某些其他代码使用该引用,则调用将不会应用AOP建议(再次,您绕过代理)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM