Choose component loading order - spring

I have a spring boot with three #Component classes.
src.main.java
|_components
|_A
|_B
|_C
I need B and C executed before A can be executed. How do I specify that?
Should I use #DependsOn annotation? Or #Order? All answers online are for #Configuration and #Bean classes

You should be able to use #DependsOn like this:
#DependsOn({"b", "c"})
#Component("a")
public class A {
}
#Component("b")
public class B {
}
#Component("c")
public class C {
}

You can use #Order(<int>) notation when your components are advice and you want one advice to run before another advice.In that case the lower the number, the higher would be the precedence.
E.g.
Advice #Order(5) will have higher precedence over #Order(10).

Related

Why doesn't Spring support the order of annotations advice at the method level?

#Component
#Aspect
#Slf4j(topic = "e")
public class NotVeryUsefulAspect{
#Pointcut("within(com.lc.aop.for_source.service.impl.AAopServiceImpl)")
public void pointCutWithinAAopService(){
}
#Pointcut("#within(com.lc.aop.for_source.service.XAnnotation)")
public void pointCutAnnotation(){
}
#Before("pointCutWithinAAopService()")
#Order(0)
public void adviceBeforeAAopService(){
log.debug("=======before aop service========");
}
#Before("pointCutAnnotation()")
#Order(-1)
public void adviceBeforeAAopService2(){
log.debug("=======before aop annotation========");
}
}
#Slf4j(topic = "e")
#Component("a")
#XAnnotation
public class AAopServiceImpl implements AopService {
#Override
public void m() {
log.debug("a -AAopServiceImpl");
}
}
Based on the advice-ordering
Consider collapsing such advice methods into one advice method per join point in each #Aspect class or refactor the pieces of advice into separate #Aspect classes that you can order at the aspect level via Ordered or #Order.
Do I understand correctly that the #Order does not work in this case? Why not suport the method level order?
I think this is a very simple function, but it can avoid some unnecessary misunderstandings about #Order
I would like to order advice by method level.
Well, the answer to your question is in the sentence directly before the one you quoted, in the very same paragraph of the very same info box:
When two pieces of the same type of advice (for example, two #After advice methods) defined in the same #Aspect class both need to run at the same join point, the ordering is undefined (since there is no way to retrieve the source code declaration order through reflection for javac-compiled classes).
That question should probably be posed to the chaps working on the springframework, that project is located at: https://github.com/spring-projects/spring-framework.
What you're asking for makes sense, but keep in mind that Order is meant to prioritize the loading of beans from the context, so it makes sense that Order needs to be applied to the Aspect and not the Pointcut itself.

How to annotate JMX beans with OSGi native annotations?

I have a JMX bean which is running on felix scr annotations (AEM 6.4.8, Java 8) and would like to refactor it so it uses OSGi annotations instead. Basically, it's pretty clear what to do, there is only one tiny little "=" that I guess needs to be escaped?
The old code looks like this:
#Component(immediate=true)
#Property(name="jmx.objectname", value={"com.mypackage.monitoring:type=HierarchyModificationListenerMbean"})
#Service
public class HierarchyModificationListenerMbeanImpl
extends AnnotatedStandardMBean
implements ListenerStats {
The refactored code would then be:
#Component(immediate=true, service = ListenerStats.class, property = {"jmx.objectname=com.mypackage.monitoring:type=HierarchyModificationListenerMbean"})
public class HierarchyModificationListenerMbeanImpl
extends AnnotatedStandardMBean
implements ListenerStats {
I am not sure how to deal with the ":type=" in this case.
Any ideas?
take a look at this page https://aem.redquark.org/2018/10/day-16-creating-jmx-mbeans-in-aem.html it looks like the property definition you have should do the trick
your code looks good to me. only thing is, do you have an interface HierarchyModificationListenerMbean? your implementation class should declare that it implements such interface
Example:
public interface MyMBean {
}
#Component(service = DynamicMBean.class, property = {
"jmx.objectname=com.yourproject.osgi:type=MyMBean"
})
public class MyMBeanImpl extends AnnotatedStandardMBean implements MyMBean {
public MyMBeanImpl() {
super(MyMBean.class)
}
}

Reading multiple entity scan packages in spring boot application

I have Spring boot application
#SpringBootApplication
#EntityScan(basePackages = {"${scan.packages}"})
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
While reading multiple entity scan packages from one property separated by comma like below?
scan.packages=com.mycompany.model.package1 ,
com.mycompany.model.package2
I got this exception :
java.lang.IllegalArgumentException: Unknown entity:
com.mycompany.model.package2.Myclass
You can scan multiple Entity like this
#EntityScan(basePackages= {"scan.packages1","scan.packages2"})
This should work
#EntityScan(basePackages = {"#{'${scan.packages}'.split(',')}"})
According to the EntityScan annotation javadoc there are three ways to define the packages where to scan for entities:
value, alias for basePackages: #EntityScan( {"scan.packages1","scan.packages2"})
basePackages, alias for value: #EntityScan(basePackages= {"scan.packages1","scan.packages2"}).
basePackagesClasses, the type safe version: #EntityScan(basePackages=E.class}.Where E was a marker interface just to underline the Entities. Please see the code bellow. It could also be an annotation.
interface E {
}
#Entity
public class Glass implements E {
// Typical code to be added here
}
Or as an annotation:
#Retention(RetentionPolicy.RUNTIME)
#interface E {
}
#Entity
#E
public class Glass implements E {
// Typical code to be added here
}
From my perspective I would choose either using directly value or basePackageClasses. If I can something easier to read I would do that, and I think that is what value does, while the basePackageClasses introduces the added benefit of type safety and I can see multiple reasons to go for that. It all depends on the context.
I hit the same problem and posted an issue on the Spring Boot issue tracker about it.
The answer was that
... As shown by #25436, #EntityScan did support property solution in 2.3 so, if we decide to reinstate support, we might want to consider how to handle multi-value properties.
So it appears some Spring Boot version did support it, but then the support was dropped again... for more info, check the Spring Boot issue linked in the quote.
try this :
#EntityScan(basePackages= {"${scan.packages1","scan.packages2}"})

How can I name a #Service with multiple names in Spring?

I need something like:
#Named({"bean1", "bean2"})
#Service({"bean1", "bean2"})
Can someone help me?
Not directly, the way you have it. But it is possible by redefining an existing #Service (or #Component) as a #Bean with either a name or list of names, it is possible.
#Service("Service-A")
public class SampleService {
public String doSomething() { return "Foo"; }
}
#Configuration
public class SampleConfig {
#Bean(name = {"Service-B", "Service-C"})
public SampleService createMirroredService(#Autowired SampleService service) {
return service;
}
}
And now you have three instances of SampleService: Service-A (your #Service), Service-B, and Service-C. This works because you define one and just have the #Bean annotated method pass through the implementation, which has the effect of creating aliases. Make sure the configuration class is picked up in the scan and it should work fine.
Note: Although this works, and there are probably other solutions as well, I can't think of a case where I would need this. Perhaps if I'm integrating with a library that already exists that I can't change. But there doesn't strike me as a serious need for this, or else they would have made value on #Component an array.
Though I think #Todd answer is totally correct. It seems it has mislead some others to follow the idea. See Autowire Map with custom class and use aliases to get the correct object reference.
Therefore I would like to add an answer here to suggest one to use the below methodology instead.
#Configuration
public class SampleConfig {
#Bean(name = {"Service-A", "Service-B", "Service-C"})
public SampleService createMirroredService() {
return new SampleService();
}
}
This would be much cleaner than the above answer, though may not answer the question properly.

How to Produce prototype objects from singleton? (Design help needed)

I'm relatively new to Spring and I've got myself dug in a hole. I'm trying to model motor cars. Each model has it's own builder object, and I have a BuilderFactory that returns the correct builder based upon user selection from a web-app.
So I'm looking for suggestions on how to approach this problem where I need to create a number of individual vehicles, but I don't know what type of vehicle I'm going to need until run-time, and each vehicle needs to be unique to the user.
What I've got at the moment is shown below. The problem I have at the moment is that because the individual builders are singletons so are the individual vehicles. I need them
to be prototypes. I know it all looks pretty horrible so I'm sure there must be a better way of doing this.
The top level from the web-app looks like;
Vehicle vehicle = vehicleBuilderFactory.getBuilder(platform).build();
My vehicleBuilderFactory looks like this;
#Service
public class VehicleBuilderFactory {
#Autowired
Discovery3Builder discovery3Builder;
#Autowired
Discovery4Builder discovery4Builder;
// Lots of #Autowired statements here.
#Autowired
FreeLander2010Builder freeLander2010Builder;
public VehicleBuilder getBuilder(Platform platform) {
switch (platform.getId()) {
case 1: return discovery3Builder;
case 2: return discovery4Builder;
// Lots of case statements here
case 44: return freeLander2010Builder;
default: return null;
}
}
}
which itself looks pretty horrible. Each individual builder looks like;
#Service
public class DefenderBuilder implements VehicleBuilder {
#Autowired
Defender defender;
// Loads of Defender specific setters ommitted
#Override
public Vehicle build() {
return defender;
}
}
and finally the individual vehicle
#Service
#Scope("prototype")
public class Defender extends Vehicle {
}
The main problem now, is that because the builders are singletons, so are the vehicles, and
I need them to be prototypes, because User A's Defender is different to user B's Defender.
You can use Spring's ObjectFactory to have it service up prototype scoped beans from a singleton scoped bean. The usage is pretty straightforward:
#Component
class DefenderBuilder implement VechicleBuilder {
#Autowired
ObjectFactory<Defender> defenderFactory;
Defender build() {
return defenderFactory.getObject()
}
}
#Component
#Scope("prototype")
class Defender {
}
This returns a new Defender on each call to defenderFactory.getObject()
Without reading too much into the detail you say you want to produce Prototype beans from a singleton possibly with a look up in the IoC container.
Section 3.4.6.1 Lookup method injection of the Spring documentation describes how this can be done without losing the Inversion of Control i.e. without your beans knowing about the bean store.
I have made use of the ServiceLocatorFactoryBean to solve a similar problem before. The class level Javadoc is excellent and contains some clear examples.
Two things:
1) You can use proxy in order to hold narrower scope from wider scope(e.g prototype from singleton)
All you need is to define the prototype component with the relevant scope and proxyMode
You can read about scoped proxy here.
2) Another thing that I have noticed is that you plan to use multiple autowired annotation.
note that you can use autowire on a list of interface and it will autowire all components that implements this interface as discussed here.
Moreover you can add a platform id to the VehicleBuilder interface and then generate a map in the constructor e.g:
Map<Integer, VehicleBuilder> vehicleBuilders;
#Autowired
public VehicleBuilderFactory(List<VehicleBuilder> vehicleBuilders) {
this.vehicleBuilders = vehicleBuilders.stream()
.collect(Collectors(x -> x.getPlatformId(), x -> x));
}
in that way you can avoid the switch case.

Resources