Why is a Spring ProxyFactoryBean implicit definition working? - java

I have the following definition:
<bean id="myInterceptor" class="info.fastpace.MyInterceptor"/>
<bean id="alikProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="myClass"/>
<property name="interceptorNames">
<list>
<value>myInterceptor</value>
</list>
</property>
</bean>
I have 2 classes defined: MyInterceptor and MyClass.
The peculiar thing is that Spring knows to invoke the interceptor before invoking class MyClass (capital M), even though the class isn't configured in the commonContext.xml file. The only hint is the myClass (lowercase m) in the proxy bean definition.
When removing the alikProxy bean definition, the interceptor isn't invoked.
How does Spring know to invoke the interceptor for MyClass using an undefined myClass ref?

Looks like you defined a bean of class MyClass, but did not give it any name explicitly, so Spring just gave it a default name myClass, based on class name MyClass.
Update
I suppose somewhere in your Spring context xml you have <context:component-scan> element.
Here is a fragment of book Spring In Action, 3rd Edition:
By default, <context:component-scan> looks for classes that are annotated with one
of a handful of special stereotype annotations:
#Component—A general-purpose stereotype annotation indicating that the class
is a Spring component
...skipped...
For example, suppose that our application context only has the eddie and guitar beans in it. We can eliminate the explicit <bean> declarations from the XML configuration by using <context:component-scan> and annotating the Instrumentalist and Guitar classes with #Component.
...skipped...
When Spring scans the com.springinaction.springidol package, it’ll find that
Guitar is annotated with #Component and will automatically register it in Spring. By default, the bean’s ID will be generated by camel-casing the class name. In the case of Guitar that means that the bean ID will be guitar.

Related

Spring: Xml based Autowiring a list of beans by interface type

With Spring it is possible to inject a list of beans by the interface class like:
#Component
public class Service {
#Autowire
private List<InterfaceType> implementingBeans;
...
}
All defined beans that implement this interface will be present in this List.
The annotation based approach is not possible for me, as the Service class is in a module that must not have spring dependencies.
I need to use this mechanism from outside via xml configuration.
<bean id="service" class="...Service">
<property name="implementingBeans">
??? tell spring to create a list bean that resolves all beans of the interfaceType.
</property>
</bean>
Does anyone know how to solve this?
EDIT: Additionally, there are more than one spring applications that use this service. So the best solution would be to handle this szenario completely via xml configuration. I can then copy the xml parts to all spriong applications that need this.
I want to avoid having a kind of initializer bean that gets the service injected and must then be copied to all spring applications.
Kind regards.
An XML-only solution would simply have you declare a <bean> of the "external" type and provide an autowire value of "byType".
Controls whether bean properties are "autowired". This is an
automagical process in which bean references don't need to be coded
explicitly in the XML bean definition file, but rather the Spring
container works out dependencies.
[...]
"byType" Autowiring if there is exactly one bean of the property type in the container. If there is more than one, a fatal error is
raised, and you cannot use byType autowiring for that bean. If there
is none, nothing special happens.
The explanation is a little confusing in that we expect multiple InterfaceType beans, but the actual field is of type List and Spring will be able to dynamically instantiate one and add all the InterfaceType beans to it, then inject it.
Your XML would simply look like
<bean id="service" class="...Service" autowire="byType">
</bean>
My original suggested solution made use of SpEL.
In the module that does have Spring dependencies, create a DTO
#Component(value = "beanDTO")
public class BeanDTO {
#Autowire
private List<InterfaceType> implementingBeans;
public List<InterfaceType> getImplementingBeans() {
return implementingBeans;
}
}
and then use SpEL to retrieve the value of implementingBeans from the beanDTO bean.
<bean id="service" depends-on="beanDTO" class="...Service">
<property name="implementingBeans" value="{beanDTO.implementingBeans}" />
</bean>
Spring will create the BeanTDO bean, inject all the beans that are of type InterfaceType. It will then create the service bean and set its property from beanDTO's implementingBeans property.
Following comments on question:
In an effort to be more JSR 330 compliant, Spring has introduced support for Java EE's javax.inject package. You can now annotate your injection targets with #javax.inject.Inject instead of #Autowired. Similarly, you can use #Named instead of #Component. The documentation has more details.

Spring throws the error: Bean definition is abstract

I need some help with next topic.
I have a hierarchy of beans, just like that:
<bean id="father" class="myPackage.Father" abstract="true"/>
<bean id="childA" class="myPackage.ChildA" parent="father">
<property name="atrib1" value="hello"></property>
</bean>
<bean id="childB" class="myPackage.ChildB" parent="father">
<property name="atrib2" value="bye"></property>
<property name="atrib3" value="other"></property>
</bean>
I need to create another bean which contains a reference to the abstract class. Then at run-time, I will need to be able to initialize a variable of TYPE "myPackage.Father" and instantiate it with any of the children classes (the polymorphism mechanism). I mean something like that:
<bean id="reference" class="myPackage.Another">
<property name="atrib4" ref="father"></property>
</bean>
Note that reference (an instance of myPackage.Another) is not a subclass of myPackage.Father. But with these lines Spring throws the next error:
Bean definition is abstract
How could I deal with it?
I appreciate any help, thanks in advance!
abstract beans are never instantiated as objects, they exist only in the form of definitions.
From the documention:http://docs.spring.io/spring/docs/3.0.x/reference/beans.html
The parent bean cannot be instantiated on its own because it is incomplete, and it is also explicitly marked as abstract. When a definition is abstract like this, it is usable only as a pure template bean definition that serves as a parent definition for child definitions. Trying to use such an abstract parent bean on its own, by referring to it as a ref property of another bean or doing an explicit getBean() call with the parent bean id, returns an error. Similarly, the container's internal preInstantiateSingletons() method ignores bean definitions that are defined as abstract.
In your case
<bean id="reference" class="myPackage.Another">
<property name="atrib4" ref="father"></property>
</bean>
is refering to the bean defined as abstract which is causing the issue.
First of all abstract bean has nothing to do with the abstract class
they don't even need to be mapped to a class.They are used to group the common properties shared by another beans.But you can not use an abstract bean as a ref to wire a property in another bean.
If your bean myPackage.Another has a reference of type myPackage.Father and your child beans are assignable (either extends of implements) to myPackage.Father then you can wire either childA or childB
in your myPackage.Another bean like this
<bean id="reference" class="myPackage.Another">
<property name="atrib4" ref="childA"></property>
</bean>
There is no different between abstract class and abstract beans.When you use beans and refer to another bean which is abstract , it means you want to instantiate an abstract class it and it can not work surely !
Be careful when you are using an abstract class ! An abstract class is used for template class and you can just extend it !

Declaration of beans in applicationContext.xml

I have a question regarding declaration of classes in applicationContext.xml
In applicationContext.xml do we need to specify all the classes from the application?
E.g.
In my small web application I have a Entity class, Service class and DAO class. So currently it is defined as
<!-- Beans Declaration -->
<bean id="Employees"
class="net.test.model.Employees" />
<!-- User Service Declaration -->
<bean id="
EmployeeService" class="net.test.employees.service.EmployeeService">
<property name="employeesDAO" ref="EmployeeDAOImpl" />
</bean>
<!-- User DAO Declaration -->
<bean id="EmployeeDAO" class="net.test.employee.dao.EmployeeDAOImpl">
<property name="sessionFactory" ref="SessionFactory" />
</bean>
So if I have multiple entity, service and dao classes do I need to mention all those classes in applicationContext.xml?
Any insight into this is highly appreciable.
Regards
Update 1
ManagedBean
#ManagedBean(name="empMB")
#Named
#Scope("request")
public class EmployeesManagedBean implements Serializable {
and I have Inject annotation
#Inject
EmployeesService employeesService;
In EmployeesService I have annotations like
#Named
public class EmployeesService implements IEmployeesService {
#Inject
EmployeesDAO employeesDAO;
#Override
public List<Employees> getEmployees() {
return getEmployeesDAO().getEmployees();
}
and finally in applicationContext.xml I have
<context:component-scan base-package="net.test" />
Now the problem is when I run my application I am getting
java.lang.NullPointerException at
net.test.managed.bean.EmployeesManagedBean.getEmpList(EmployeesManagedBean.java:53)
What am I doing wrongly to get nullpointer exception?
In applicationContext.xml do we need to specify all the classes from
the application?
No. Declaring model classes like your net.test.model.Employees is pointless unless you need a prototype to work with, something like initializing its values, but you can do this directly in the class and just instantiate it.
So if I have multiple entity, service and dao classes do I need to
mention all those classes in applicationContext.xml?
As I explained before, entity classes no. Services and DAOs are ok because most of the time you need DAOs injected to the Services (and that's the point of DI). But of course, if you create 3 DAOs and you want them to be injected in your 3 Services, then mention them in your Spring XML Bean Definition file (what you call applicationContext.xml).
But one thing, you may want to use package scanning autodetection and annotation based config to avoid writing everything in your Bean Definition File.
The bean declaration in the application context is to register the bean in the application container.
If the bean is not registered, the container wouldn't be able to dependency inject any instance of that class, or apply interceptors to the object of the class.
So unless the reference of bean is not required for any task like intercepting it or inject it, or create default singleton object of it, there is no need to declare it in the applicationContext.xml
Hope this helps.
Ideally yes, another way can be using Spring Annotations so that you don't to add multiple entries in xml.

Updating Spring xml configured controller to Annotations

I have been tasked with updating a old project that I did not write.
The project is Spring MVC based and has an older Spring Controller configuration that I am unfamiliar with.
The controllers have bean configurations as follows
<bean id="controllerName" class="the.project.controller.class">
<property name"serviceName">
<ref bean="serviceName">
</property>
<property name"successView">
<value>viewName</value>
</property>
</bean>
where serviceName refers to a class annotated with #Service as follows
#Service(value=serviceName)
Is this the correct replacement for the xml configuration ?
#Autowired
#Qualifier("serviceName")
ServiceNameImpl serviceName
thanks
edit here is the organization of the serviceName class and interface
public interface ServiceName {
// methods omitted
}
#Service(value="serviceName")
public class ServiceNameImpl implments ServiceName {
//methods omitted
}
The #Resource annotation is not available to me ( Spring 3.0.7) and Autowire as above fails ( as it appears the type is not as expected as described below )
org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching beans of type [the.project.ServiceNameImpl] found for dependency
Given the edits, what am I doing wrong here ( Apologies for leaving out this information )?
in the end I need to be able to access the methods of the interface and its implementation
for example
serviceName.doSomething(someVar);
That's correct, but consider using private modifier for serviceName. Another way would be to use #Resource:
#Resource
private ServiceNameClass serviceName;
Note that in this case you don't need a #Qualifier("serviceName") - #Resource autowires by (field) name while #Autowired uses type by default. Only a problem when you have several beans of the same/compatible type.
Also you can skip the controllerName bean definition altogether by annotating controller class with #Controller.
BTW you can also shorten the XML configuration a bit by using the following syntax:
<bean id="controllerName" class="the.project.controller.class">
<property name"serviceName" ref="serviceName"/>
<property name"successView" value="viewName"/>
</bean>
(IntelliJ suggests this transformation and performs it for you).

Spring #Autowired with 2 beans of the same type

I have the following defined.
#Autowired
DaoType1<object1> someDao;
#Autowired
DaoType1<object1> someListDao;
and in my bean definitions I have two beans of the same type
<bean id="someDao" class="com.example.DaoType1" />
<bean id="someListDao" class="com.example.DaoType1" />
The second bean is imported from another xml file if that makes a difference. They have different properties being set as well. Why is spring not throwing an error because 2 beans of the same type have been defined. Does it use the variable names since they match the bean ids. The dao's are different and the functionality works as expected if I had used #Qualifiers for the two different beans.
Here is a more concise version. I've left out other beans since I they are not relevant.
applicationContext.xml
<import resource="classpath:dm-services-crud.xml"/>
<bean id="ruleListCrudService" class="com.idna.dm.service.crud.impl.RuleCrudServiceImpl">
<property name="crudDao" ref="ruleListCrudDao" />
</bean>
dm-services-crud.xml
<bean id="ruleCrudService" class="com.idna.dm.service.crud.impl.RuleCrudServiceImpl">
<property name="crudDao" ref="ruleCrudDao" />
<property name="ruleNetworkOfNodesCrudService" ref="ruleNetworkOfNodesCrudService" />
<property name="elementMappingsCrudService" ref="elementMappingsCrudService" />
<property name="ruleCrudDao" ref="newRuleCrudDao"/>
</bean>
default-autowire is not present in any of my xml files at all.
This appears to be expected behaviour. The documentation says:
byName
Autowiring by property name. Spring looks for a bean with the same name as the property that needs to be autowired. For example, if a bean definition is set to autowire by name, and it contains a master property (that is, it has a setMaster(..) method), Spring looks for a bean definition named master, and uses it to set the property.
I guess this means you have specified default-autowire="byName" in your applicationContext.xml.
However, refactoring may affect this in an unpredictable way. That's why (I think) it is advisable to switch to autowiring by type, and disambiguate the beans by the use of
#Qualifier (as you noted)
#Resource rather than #Autowired (as skaffman noted)
The #Autowired annotation behaves slightly differently to the "autowire by type" specification on xml based bean definitions.
When using annotations you're not technically doing an auto wire... you're setting the value based on the annotation. The autowire annotation has the same function as the xml property element.

Categories

Resources