JSR-330 #Scope and Spring Don't Match - spring

The java doc for the JSR-330 Scope annotation states "uses the instance for one injection, and then forgets it" implying that the instance is of scope prototype and the Singleton annotation is intended to create the singleton that is the default behavior with spring. So the question is, Why, when I use the Named annotation rather than the Spring Component annotation does Spring not follow the JSR guidelines and scope the bean as prototype? It seems to me like it should.
I would like to keep the spring dependencies consolidated to a single module and use JSR-330 everywhere else so If needed I can easily switch later.

So this is how I made what I want work:
/**
* JSR-330 assumes the default scope is prototype, however Spring IOC defaults to singleton scope.
* This annotation is used to force the JSR-330 standard on the spring application.
*
* This is done by registering this annotation with the spring bean factory post processor.
* <pre>
* <code>
* public class PrototypeBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
*
* public void postProcessBeanFactory(ConfigurableListableBeanFactory factory) throws BeansException {
* for (String beanName : factory.getBeanDefinitionNames()) {
* if (factory.findAnnotationOnBean(beanName, Prototype.class) != null) {
* BeanDefinition beanDef = factory.getBeanDefinition(beanName);
* beanDef.setScope("prototype");
* }
* }
* }
* }
* </code>
* </pre>
*
* #see javax.inject.Scope #Scope
*/
#Scope
#Documented
#Retention(RUNTIME)
public #interface Prototype {}
I put this annotation in my core jar and then let the spring-boot app module do the work of processing the annotation.
It works well for me but I am happy to hear any other suggestions.

Related

Spring AOP with aspectj #annotation [duplicate]

This question already has an answer here:
Emulate annotation inheritance for interfaces and methods with AspectJ
(1 answer)
Closed 1 year ago.
I want to apply annotation with aspectJ. (Use Springboot 1.5.1, Mybatis 2.1.1)
So, I made custom annotation and AspectJ.. and apply it.
/** CustomAnnotation */
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public #interface TestAnnotation {
String value();
}
/** AspectJ configuration */
#Component
#Aspect
public class AuditTrailAspect {
#Autowired
TestDAO dao;
#Around("#annotation(TestAnnotation)")
public Object doSomethingAround(ProceedingJoinPoint joinPoint) throws Throwable {
/* before proceed */
Object result = joinPoint.proceed();
/* after proceed */
return result;
}
}
/** Apply Annoataion at Repository */
#Repository
public interface TestDAO {
#TestAnnotation(value = "test")
int insertSomething(RequestDto dto);
}
(this code made simple, for question)
if pointcut expression apply 'execution' this code works fine in Repository(DAO)..
also if pointcut expression apply '#annotation' this code works other Component(Service.. Controller)
But, Why can't I apply custom annotation in Repository(DAO) with AspectJ?
please help.. Thank you!
Annotations on implemented interfaces cannot be inherited.
#Inherited causes annotations (only on class) to be inherited from superclasses , but no effect for interface implementations.
Note that this meta-annotation type has no effect if the annotated
type is used to annotate anything other than a class. Note also that
this meta-annotation only causes annotations to be inherited from
superclasses; annotations on implemented interfaces have no effect.

Configuring Spring to ignore dependencies annotated with #Inject

I have an EJB class in which I need to inject two beans - one should be injected by the EJB container and other is a Spring Container.
#Stateless
#Interceptors(SpringBeanAutowiringInterceptor.class)
#LocalBean
public class SomeClass {
#Inject
private EJBClass a;
#Autowired
private SpringComponent b;
}
Here, the Spring interceptor trying to intercept the injection of bean 'a' and it's getting failed. I want the EJB container to inject the bean 'a' and Spring container to inject bean 'b'.
Please show me a way out here.
By customizing the SpringBeanAutowiringInterceptor class, dependencies annotated with #Inject can be excluded from auto wiring.
To understand what happens behind the scene, have a look at source code of
SpringBeanAutowiringInterceptor.java -
/**
* Actually autowire the target bean after construction/passivation.
* #param target the target bean to autowire
*/
protected void doAutowireBean(Object target) {
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
configureBeanPostProcessor(bpp, target);
bpp.setBeanFactory(getBeanFactory(target));
bpp.processInjection(target);
}
At first line, of doAutowireBean, a new instance of AutowiredAnnotationBeanPostProcessor is created. Here set of annotations to be scanned for auto wiring dependencies are configured.
/**
* Create a new AutowiredAnnotationBeanPostProcessor
* for Spring's standard {#link Autowired} annotation.
* <p>Also supports JSR-330's {#link javax.inject.Inject} annotation, if available.
*/
#SuppressWarnings("unchecked")
public AutowiredAnnotationBeanPostProcessor() {
this.autowiredAnnotationTypes.add(Autowired.class);
this.autowiredAnnotationTypes.add(Value.class);
try {
this.autowiredAnnotationTypes.add((Class<? extends Annotation>)
ClassUtils.forName("javax.inject.Inject", AutowiredAnnotationBeanPostProcessor.class.getClassLoader()));
logger.info("JSR-330 'javax.inject.Inject' annotation found and supported for autowiring");
}
catch (ClassNotFoundException ex) {
// JSR-330 API not available - simply skip.
}
}
Since, by default, the #Inject annotation is configured spring scans respective dependencies marked with #Inject and tries to auto wire them.
To exclude #Inject annotated dependencies write below custom class.
public class CustomSpringBeanAutowiringInterceptor extends SpringBeanAutowiringInterceptor {
/**
* Template method for configuring the
* {#link AutowiredAnnotationBeanPostProcessor} used for autowiring.
* #param processor the AutowiredAnnotationBeanPostProcessor to configure
* #param target the target bean to autowire with this processor
*/
protected void configureBeanPostProcessor(AutowiredAnnotationBeanPostProcessor processor, Object target) {
Set<Class> annotationsToScan = new HashSet<Class>();
annotationsToScan.add(Autowired.class);
annotationsToScan.add(Value.class);
processor.setAutowiredAnnotationTypes(annotationsToScan);
}
}
Here configureBeanPostProcessor hook is utilized to customize the bean post processor so as to include only those annotations which we require to be auto wired.
After applying this custom class as interceptor in code the desired behaviour can be achieved
#Stateless
#Interceptors(CustomSpringBeanAutowiringInterceptor.class)
#LocalBean
public class SomeClass {
#Inject
private EJBClass a;
#Autowired
private SpringComponent b;
}
Let know in comments if you face any issues. Also feel free to optimize the code as deemed fit and excuse any compilations / formatting issues.
Use #EJB annotation to inject EJB

Spring Boot application is ignoring java config

I have a fairly simple Spring Boot app I am working on that uses a few Java Config classes. However, it seems that the configuration is not being picked up. I have break points all over, but nothing gets tripped. I even tossed a few RuntimeExceptions just to see if maybe my debugger was on the fritz.
In my main class, I have the standard Spring Boot main:
#ComponentScan
#EnableAutoConfiguration
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
As you can see, I tagged it with #ComponentScan and #EnableAutoConfiguration. The Application class lives at the root of the classpath. My understanding of the #ComponentScan annotation is that it will search for all configuration classes beneath it.
In a package one layer down I have all the config classes:
My "Common" configuration
#Configuration
#EnableJpaRepositories("com.codechimp.XXX.repository")
#EnableTransactionManagement
public class AppCommonConfig {
#Inject
private Environment environment;
/* Define common beans here like datasource and such */
}
And my Spring Security configuration
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Inject
private LocalXXXUserDetailsService localXXXUserDetailsService;
/**
* #see org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter#configure(HttpSecurity)
*/
#Autowired
protected void configure(HttpSecurity http) throws Exception {
// Configure http
}
/**
* #see org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter#configureGlobal(AuthenticationManagerBuilder)
*/
#Autowired
protected void configureGlobal(AuthenticationManagerBuilder auth)
throws Exception {
// Configure auth
}
}
However, when I run the app, it doesn't seem to call any of the methods in either of these config classes. It's as if they are being completely ignored. As I said, I have tried setting break points and even throwing a RuntimeException right in the beginning of all the methods like so:
if (true)
throw new RuntimeException("Break!");
Admittedly I have not had much experience with using Java Config, but I have been over the docs again and again and I am not seeing the missing piece(s).
I think you need your Application to be a #Configuration.
It's not a great idea to do a #ComponentScan from the default package (I assume that's what you mean by "the root of the classpath"). That would definitely switch some things off, but more seriously it causes a huge scan of all jars on your classpath, which is not a great idea (and can cause the app to fail).
You need to add
#SpringBootApplication
to your Spring Boot main class. From the docs:
/**
* Indicates a {#link Configuration configuration} class that declares one or more
* {#link Bean #Bean} methods and also triggers {#link EnableAutoConfiguration
* auto-configuration} and {#link ComponentScan component scanning}. This is a convenience
* annotation that is equivalent to declaring {#code #Configuration},
* {#code #EnableAutoConfiguration} and {#code #ComponentScan}.
*
* #author Phillip Webb
* #author Stephane Nicoll
* #since 1.2.0
*/

How do you use a bean from an another class in a class?

Using xml, I was able to define a common xml file, where i can put common bean which are used for other differect condig file.
I move my config to psring java config, how to achieve this with java config?
let's say I have my common class as :
#Configuration
public class Common {
#Bean
public A a(){
return new A();
}
}
and I want to use it as
#Configuration
public class AConfig {
#Bean
public ABB abb(){
ABB abb = new ABB();
//TODO abb.set ????
return abb;
}
}
The TODO part is missing, I want to use the a() from the common class.
Is that possible?
The simplest approach is just to 'Autowire' in a private member like this:
#Configuration
public class AConfig {
#Autowire
private A myA;
#Bean
public ABB abb(){
ABB abb = new ABB();
abb.setA(myA); // or MUCH better, make the A member of ABB private final and overload a construtor
return abb;
}
}
The reason this works is that AConfig is a Bean too. It has to be constructed by the Spring Bean Factory. After construction, the Post Construction activities take place - one of those being processing post construction annotations such as Autowired. So 'myA' will be set before it is used in the #Bean annotated method.
From the #Import annotation Javadoc:
* <p>Provides functionality equivalent to the {#code <import/>} element in Spring XML.
* Only supported for classes annotated with {#code #Configuration} or declaring at least
* one {#link Bean #Bean} method, as well as {#link ImportSelector} and
* {#link ImportBeanDefinitionRegistrar} implementations.
*
* <p>{#code #Bean} definitions declared in imported {#code #Configuration} classes
* should be accessed by using {#link org.springframework.beans.factory.annotation.Autowired #Autowired}
* injection. Either the bean itself can be autowired, or the configuration class instance
* declaring the bean can be autowired. The latter approach allows for explicit,
* IDE-friendly navigation between {#code #Configuration} class methods.
*
* <p>May be declared at the class level or as a meta-annotation.
*
* <p>If XML or other non-{#code #Configuration} bean definition resources need to be
* imported, use {#link ImportResource #ImportResource}
I presume that if you import the #Configuration class itself, the "latter approach", you'd then just explicitly call the #Bean method on the imported class, e.g.
#Configuration
#Import(BarConfiguration.class)
public class FooConfiguration {
#Autowired
private BarConfiguration barConfiguration;
#Bean
public Foo foo() {
Foo foo = new Foo();
foo.setBar(barConfiguration.bar());
return foo;
}
}

Spring IoC container - Define dependency on classes annotated with a specific annotation?

I have a bean which scans for classes annotated with a particular annotation (a domain specific one). I want to ensure that all the beans annotated with #MyDomainAnnotation are initialised and instantiated before the bean which scans for beans annotated with #MyDomainAnnotation.
Is there a way to define such a dependency as this is part of a framework and therefore new classes might be "plugged in". Basically I don't know the classes' names beforehand.
Implement ApplicationListener<ContextRefreshedEvent> on your scanning bean.
public class MyScanningBean implements ApplicationListener<ContextRefreshedEvent> {
private boolean scanned = false;
#Override
public void onApplicationEvent(ContextRefreshedEvent event) {
/* Published when the ApplicationContext is initialized or refreshed,
* for example, using the refresh() method on the
* ConfigurableApplicationContext interface. "Initialized" here means
* that all beans are loaded, post-processor beans are detected and
* activated, singletons are pre-instantiated, and the
* ApplicationContext object is ready for use. */
if (!scanned) {
// scan for beans
scanned = true;
}
}
}
See http://static.springsource.org/spring/docs/3.2.x/spring-framework-reference/html/beans.html#context-functionality-events
Although I opted for implementing ApplicationListener as #Tichodroma suggested I also found another solution which sometimes might be what you want if you need some more fine-grained control over the order of beans' initialisation. So implementing SmartLifecycle you can provide phase values which will determine the sequence (in ascending order) in which your beans are instantiated (i.e. beans having smallest phase values will be initialised first).
But anyway I think the above answer is more elegant and clean in my case.

Resources