I would like to use Spring's bean inheritance while employing the @Bean
-type definition of beans. Specifically, let
public class Serwis {
Integer a;
Integer b;
Map<Integer, Integer> m = new HashMap<>();
}
and suppose the xml-based configuration would look like:
<bean id="absSerwis" class="service.Serwis"
p:a="11">
<property name="m">
<map>
<entry key="111" value="111"></entry>
</map>
</property>
</bean>
<bean id="defSerwis" parent="absSerwis"
p:b="12"
/>
which does create the bean defSerwis
containing a deep copy of the bean absSerwis
; in particular the contents of m
are copied. Now, I would like to define beans like defSerwis
using @Bean
annotations, like
@Autowired
@Qualifier("absSerwis")
private Serwis absSerwis;
@Bean
public Serwis cccSerwis() {
Serwis s = new Serwis();
BeanUtils.copyProperties(absSerwis, s); //wrong; does shallow copy
return s;
}
what is the proper way to do it?
For starters what you describe isn't what actually happens. There is no such thing as a deep copy or anything else being made. Lets first investigate what Spring does when using a parent
bean. (Also note that it is about bean-definition inheritance NOT class inheritance !);
Given your configuration
<bean id="absSerwis" class="service.Serwis"
p:a="11">
<property name="m">
<map>
<entry key="111" value="111"></entry>
</map>
</property>
</bean>
<bean id="defSerwis" parent="absSerwis"
p:b="12"
/>
What happens is that for the defSerwis
definition it takes the configuration of the parent absSerwis
and itself and merges this into a full bean definition. There is thus no such thing as deep copies or copies of beans.
What Spring eventually sees
<bean id="absSerwis" class="service.Serwis"
p:a="11">
<property name="m">
<map>
<entry key="111" value="111"></entry>
</map>
</property>
</bean>
<bean id="defSerwis" class="service.Serwis"
p:a="11" p:b="12"
<property name="m">
<map>
<entry key="111" value="111"></entry>
</map>
</property>
/>
See also this section of the reference guide.
The easiest way is to create a method that constructs your parent, and add from there. This method must not be annotated with @Bean
.
@Configuration
public class MyConfiguration {
private Serwis baseSerwis() {
Serwis base = new Serwis();
base.setA(11);
Map map = new HashMap();
map.put(111, 111);
base.setM(map);
return base;
}
@Bean
public Serwis absSerwis() {
return baseSerwis();
}
@Bean
public Serwis defSerwis() {
Serwis defSerwis = baseSerwis();
defSerwis.setB(12);
return defSerwis;
}
}
This is more or less the equivalent of the xml part.
If you would like to make a deep copy of object then you could:
1) program it yourself to do so.
2) use java serialization to do so (serializing and deserializing could create a deep copy), but this requireas that all objects in your data structure implements the serializable interface. There are also other liberaries that could be used for that (xStream for instance).
3) Spring by default creates only one instance of a particular bean (aka Singleton), you could annotate it with @Prototype to let Spring know that you would like to get a new object each time you need it.
By using a builder + copy method
public class Serwis {
Integer a;
Integer b;
Map<Integer, Integer> m = new HashMap<>();
private Serwis(Builder builder) {
a = builder.a;
b = builder.b;
m = builder.m;
}
public static Builder builder() {
return new Builder();
}
public Builder copy(Serwis copy) {
return builder()
.a(a)
.b(b)
.m(m);
}
public static final class Builder {
private Integer a;
private Integer b;
private Map<Integer, Integer> m = new HashMap<>();
private Builder() {
}
public Builder a(Integer val) {
a = val;
return this;
}
public Builder b(Integer val) {
b = val;
return this;
}
public Builder m(Map<Integer, Integer> val) {
m.putAll(val);
return this;
}
public Serwis build() {
return new Serwis(this);
}
}
}
And the configuration class like this:
@Autowired
@Qualifier("absSerwis")
private Serwis absSerwis;
@Bean
public Serwis cccSerwis() {
return absSerwis.copy().build();
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.