When and how cglib-proxied component instance is created - java

I'd like to learn if there are some rules / conditions that a Spring component is wrapped (proxied) by CGLIB. For example, take this case:
#Component
public class TestComponent {
}
#Service
//#Transactional(rollbackFor = Throwable.class)
public class ProcessComponent {
#Autowired
private TestComponent testComponent;
public void doSomething(int key) {
// try to debug "testComponent" instance here ...
}
}
If we let it like this and debug the testComponent field inside the method, then we'll see that it's not wrapped by CGLIB.
Now if we uncomment the #Transactional annotation and debug, we'll find that the instance is wrapped: it's of type ProcessComponent$$EnhancerByCGLIB$$14456 or something like that. It's clearly because Spring needs to create a proxy class to handle the transaction support.
But I'm wondering, is there any way that we can detect how and when does this wrapping happen ? For example, some specific locations in Spring's source code to debug into to find more information; or some documentations on the rules of how they decide to create a proxy.
For your information, I need to know about this because I'm facing a situation where some component (not #Transactional, above example is just for demonstrating purpose) in my application suddenly becomes proxied (I found a revision a bit in the past where it is not). The most important issue is that this'll affect such components that also contain public final methods and another issue (also of importance) is that there must have been some unexpected changes in the design / structure of classes. For these kind of issues, of course we must try to find out what happened / who did the change that led to this etc...
One note is that we have just upgraded our application from Spring Boot 2.1.0RELEASE to 2.1.10RELEASE. And checking the code revision by revision up till now is not feasible, because there have been quite a lot of commits.
Any kind of help would be appreciated, thanks in advance.

You could debug into org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.getAdvicesAndAdvisorsForBean(Class, String, TargetSource).
If any advisor is found, the bean will be proxied.

If you use a #Lookup method injection it will also proxy the component class.

Related

Using AOP and DI itself causes Spring ApplicationListener to be fired twice

Software versions
Spring Version 5.3.18 and earlier
JDK Version 1.8.0_202
Overview
When I use Spring ApplicationListener, in order to prevent transaction invalidation, my ApplicationListener implementation class writes the following code (of course, the code can be written differently to avoid this problem), which will cause my listener to trigger twice after the event is published. I think it's not normal, but not sure if it's a bug, so I want to ask everyone's opinion.
#Component
public class EventDemoListener implements ApplicationListener<EventDemo> {
#Autowired
DemoService1 demoService1;
#Autowired
DemoService2 demoService2;
#Autowired
EventDemoListener eventDemoListener;
#Override
public void onApplicationEvent(EventDemo event) {
eventDemoListener.testTransaction();
System.out.println("receiver " + event.getMessage());
}
#Transactional(rollbackFor = Exception.class)
public void testTransaction() {
demoService1.doService();
demoService2.doService();
}
}
Through this demo project, this problem can be reproduced. Please read the README.md document before running.
https://github.com/ZiFeng-Wu/spring-study
Analysis
After analysis, because here DI itself , When EventDemoListener is created, property filling will trigger DefaultSingletonBeanRegistry#getSingleton(String, boolean) in advance.
Then singletonFactory.getObject() executed in getSingleton() will cause the unproxyed EventDemoListener object to be put into AbstractAutoProxyCreator#earlyProxyReferences.
After the properties are filled, calling AbstractAutowireCapableBeanFactory#initializeBean(String, Object, RootBeanDefinition) and executing ApplicationListenerDetector#postProcessAfterInitialization(Object, String) will cause the unproxyed EventDemoListener object to be put into the AbstractApplicationEventMulticaster.DefaultListenerRetriever#applicationListeners container.
Then when the event is published, execute AbstractApplicationEventMulticaster.DefaultListenerRetriever#getApplicationListeners() and use ApplicationListener<?> listener =beanFactory.getBean(listenerBeanName, ApplicationListener.class) to obtain the listener is the proxied EventDemoListener object.
At this time, there are only unproxyed EventDemoListener object in the applicationListeners container, so the proxied EventDemoListener object will be added to the final returned allListeners collection, as shown in the figure below, which will eventually cause the listener to be triggered twice.
Updated answer
Now with your updated GitHub project, I can reproduce the problem. It also occurs when using a Spring AOP aspect targeting the listener class, not just in the special case of self-injection + #Transactional. IMO, it is a Spring Core bug, which is why I created PR #28322 in order to fix the issue #28283 you raised either before or after cross-posting here. You should have linked to that issue in your question, I just found it because I was searching for key words before creating an issue for it myself.
See also my comment in the issue, starting with this one.
Original answer (for reference)
OK, in your main class I changed
String configFile = "src/main/resources/spring-context.xml";
AbstractApplicationContext context = new FileSystemXmlApplicationContext(configFile);
to
AbstractApplicationContext context = new AnnotationConfigApplicationContext("com.zifeng.spring");
Now the application starts, also without DB configuration. It simply prints:
receiver test
There is no exception. I.e., if for you it does not work, probably there is a bug in your XML configuration. But actually, you really do not need it, because you used component and service annotations already.
So if I need a database setup in order to reproduce this, please, like I said in my comment, update the project to provide an H2 configuration which works out of the box.

Is it possible to create necessary / required interfaces?

i have a little kont in my brain about structuring our code. We have a REST Backend based on SpringBoot. To handle requests regarding to security checks we use HandlerInterceptors. In some specific cases we need a specific interceptor and not our default one. The default one is registered in a 3rd party lib that no one can forget it. But i want all coders to think about this specific interceptor.
Actually, i just said it to them to achieve this.
Here's my question: Is there an option to create required (or necessary) interfaces which must be implemented? This would be a way to provide our security code by lib and to have the security that every coder implemented our specific interface (also if he just does nothing with it).
pseudo code:
public interface thinkForIt(){
Object SecBean specificSecBean;
public void methodToThinkOn();
}
public SecImpl implements thinkForIt(){
#Override
public void methodToThinkOn(){
return null; // i thought about it but i do not need to do anyting!
}
If the interface thinkForIt would have any annotations like #required, users could get warning or error if they did not implement it...
Looking for a solution and thanks for your comments in advance!
Your overall design is questionable; you are reinventing security code, which is always a red flag. Use Spring Security instead.
However, there's a simple way to ensure that "some bean of type Foo" has been registered with the context:
#Component
#RequiredArgsConstructor
public class ContextConfigurationVerifier {
final Foo required;
}

Apache Felix - How to guarantee injecting of dynamic references before an activate method

Here is snippet of intrested case:
We have some configuration class it can have multi instances. It suppose that we supply several configurations in one bundle. It's one scope.
#Service
#Component
public class SampleConfigurationImpl implements SampleConfiguration {
// declaration of some properties, init method and etc...
}
Also we have a service which uses these configurations:
#Service
#Component
public class SampleServiceImpl implements SampleService {
#Reference(
referenceInterface = SampleConfiguration.class,
cardinality = ReferenceCardinality.OPTIONAL_MULTIPLE,
policy = ReferencePolicy.DYNAMIC)
private Map<String, SampleConfiguration> sampleConfigurations = new ConcurrentHashMap<>();
private void bindSampleConfigurations(SampleConfiguration sampleConfiguration) {
sampleConfigurations.put(sampleConfiguration.getName(), sampleConfiguration);
}
private void unbindSampleConfigurations(SampleConfiguration sampleConfiguration) {
sampleConfigurations.remove(sampleConfiguration.getName());
}
#Activate
private void init() {
System.out.println(sampleConfigurations.size());
}
}
So, can I get some guarantees that on invocation of init method all configurations are injected (at least of current bundle)? Maybe there is some alternative way to do this. I understand that another bundles can bring new configurations and it's unreal to get guarantees but it's intrested in case of only one bundle.
On practice it can be case when in init method there are only part of configurations. Especially if it's more difficalt case when you have several types of configuration or one service uses another one which has dynamic references and first service relies on fact that everything is injected.
The most unpleasant is that it can bind/unbind configurations both before and after init method.
Maybe there is some way to guarantee that it bind always after init method...
I'm interested in any information. It will be great to get answer on two questions (guarantees before or after). Probably someone has experience how to resolve such problem and can share with me.
Thanks.
No, not that I know of. What I usually do in that case (depending on your use case, it depends on if your activation code is ok with running multiple times) is to create a 'reallyActivate' method I call both from the regular activate and from the bindSampleConfigurations (+ setting an isActivated flag in activate). Then I can perform some logic every time a new SampleConfiguration gets bound, even if it's after the activation. Does that help for your case?

Accessing Magnolia TemplatingFunctions from inside a controller

Is it possible to serve different experiences depending on whether the user is in edit mode? I've noticed that the following method exists; however it is not static:
info.magnolia.templating.functions.TemplatingFunctions.isEditMode()
Is there a way to access the isEditMode() method from inside a controller? Is an instance of it defined somewhere which can be accessed? I imagine that creating a new instance of the TemplatingFunctions class won't help ...
I've looked at using #Inject; however I keep getting issues on injection of all parameters.
#Inject
public ModelAndView renderView(Model model, Node node, TemplatingFunctions templatingFunctions) throws RepositoryException {
if (templatingFunctions.isEditMode()) {
}
}
When I checked what that method does, I found out that its a combination of two functions.
Components.getComponent(ServerConfiguration.class).isAdmin()
and
aggregationStateProvider.get().isPreviewMode()
It seems that you should be injecting a provider to know if user is in preview mode
Provider<AggregationState> aggregationStateProvider
As a general remark, one may understand if a component is injectable or not from the related modules configuration which is under myModule/src/main/resources/META-INF/mymodule.xml. If a component is listed there, then is it injectable in other classes. For instance you should have no problems injecting a type of TemplatinFunctions because it is indeed defined as;
<component>
<type>info.magnolia.templating.functions.TemplatingFunctions</type>
<implementation>info.magnolia.templating.functions.TemplatingFunctions</implementation>
<scope>singleton</scope>
</component>
Further reading can be found at https://documentation.magnolia-cms.com/display/DOCS/Dependency+injection+and+inversion+of+control
Hope this helps,

Not loading a Spring bean when a certain profile is set

Background: So, I've got several beans that interface external systems. For development, it's convenient to mock the external systems and replace the interfacing beans with some implementations that produce more or less static responses. So what I've been doing is to create an interface, the real implementation and a stub implementation like this:
public interface ExternalService {
// ...
}
#Service
public class ExternalServiceImpl implements ExternalService {
// ...
}
#Service
#Primary
#Profile({"stub"})
public class StubExternalService implements ExternalService {
// ...
}
...and this works great: if the stub profile is not present, the stub-bean does not get loaded at all. If it is present, it nicely supersedes the real implementation because of the #Primary annotation.
Problem: Now, however, I've run for the first time in a situation where I've actually got two real implementations of the same interface. One of them is defined as primary, but the other may also be used by loading it from the application context.
I'd still like to create a stub service to replace them both, but this time my old way of defining the stub as #Primary doesn't work, because there's already one primary implementation. Basically what I'd need is a way of not loading the primary bean when the stub profile is set, but I'm at loss on how exactly to do that. Web searches or other Stack Overflow questions don't seem to be helping.
Turns out the answer was surprisingly simple: you add a not-operator (!) in front of the profile name:
#Service
#Primary
#Profile({"!stub"})
public class ExternalServiceImpl implements ExternalService {
// ...
}
This way the bean is only loaded when the stub-profile is not active. The support for this feature was added in Spring 3.2 M1.
There's one caveat, though: if you write #Profile({"!stub", "foo"}), the comma is treated as "or", not "and". So this example bean would be activated either if stub was not active or if foo was active.
Edit/Add: Spring 5.1 added a support for a new expression language for profiles: !stub & foo is activated when stub is not active and foo is active. Great success! You can even mix and match ands and ors provided that you use parenthesis: production & (us-east | eu-central).

Categories