I want to create Clazz, where I can create two Beans with the same class, but with the different configuration.
public class Clazz {
//same class : Client, inside has the different configuration
//inicilized by methods
#Bean(name="Bean1")
public Client1 (){}
#Bean(name = "Bean2")
public Clien2t (){}
}
Then I want to inject them in other classes
public class ClassForInjectBean1{
#Autowired
#Qualifier("Bean1")
#NotNull
Client client
....
}
public class ClassForInjectBean2{
#Autowired
#Qualifier("Bean2")
#NotNull
Client client
....
}
I have tried this construction in classes ClassForInjectBean1 and ClassForInjectBean2
#Resource(name = "Bean2")
#NotNull
Client client
and
#Autowired
#Qualifier("Bean2")
But spring does not understand
Ошибка :
Parameter 1 of constructor in ClassForInjectBean1 required a single bean, but 2 were found:
- Bean1: defined by method 'Client1' in class path resource...
- Bean2: defined by method ''Client2' in class path resource...
Why I can't do that?
I know that there is this way https://www.baeldung.com/spring-qualifier-annotation, but I don't to create many classes and interfaces.
Try to use #Configuration.
Indicates that a class declares one or more #Bean methods and may be
processed by the Spring container to generate bean definitions and
service requests for those beans at runtime
I provided some example for you.
#Configuration
public class Cfg {
#Bean("client1")
public Client client1() {
return new Client("client1");
}
#Bean("client2")
public Client client2() {
return new Client("client2");
}
}
public class Client {
private String name;
public Client(String name) {
this.name = name;
}
#Override
public String toString() {
return "Client{" +
"name='" + name + '\'' +
'}';
}
}
#Component
public class InjectionTest {
#Component
public class ClassForInjectBean1 {
private final Client client;
public ClassForInjectBean1(#Qualifier("client1") Client client) {
this.client = client;
}
#PostConstruct
public void testInit() {
System.out.println(client.toString());
}
}
#Component
public class ClassForInjectBean2 {
private final Client client;
public ClassForInjectBean2(#Qualifier("client2") Client client) {
this.client = client;
}
#PostConstruct
public void testInit() {
System.out.println(client.toString());
}
}
}
Output would be:
Client{name='client2'}
Client{name='client1'}
Related
In Spring it's easy to autowire beans and have them available anywhere in the app context. Beans can be specialized to a scope such as session/request/web socket etc.
I have a rather unique scenario. I receive a message from a message broker which means the request is not received in a "Controller". Because of this, Spring is not creating #RequestScope beans (All of this logic in Spring is based on using the #Controller/#RequestMapping annotations / DispatchServlet handler).
Is there a way to create a bean within the request scope with the Spring AutowireCapableBeanFactory or some other way?
I want to do something like the below in which the SomeService.handle will be able to access the getName() method of the RequestScopeBean. Currently it throws this exception.
Exception:
BeanCreationException: Error creating bean with name '
scopedTarget.getRequestUtils': Scope 'request' is not active for the
current thread; consider defining a scoped proxy for this bean
Code
#Service
public class MyMessagingReceiver implements SomeMessageReceiver {
private final SomeService someService;
#Autowired
public MyMessagingReceiver(final SomeService someService) {
this.someService = someService;
}
public void onMessage(MessageObject messageObject) {
//possible here to use AutowireCapableBeanFactory in inject the RequestScopeBean bean?
someService.handle(messageObject);
}
}
#Service
public class SomeService {
private final RequestScopeBean requestScopeBean;
#Autowired
public SomeService(RequestScopeBean requestScopeBean) {
this.requestScopeBean = requestScopeBean;
}
public void handle(MessageObject messageObject) {
System.out.println(this.requestScopeBean.getName());
}
}
#Configuration
public class BeanDeclarations {
#Bean
#RequestScope
public RequestScopeBean requestScopeBean() {
return new RequestScopeBean();
}
}
public RequestScopeBean {
private String name;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
public class Interceptor extends HandlerInterceptorAdapter {
private RequestScopeBean requestScopeBean;
#Autowired
public Interceptor(RequestScopeBean requestScopeBean) {
this.requestScopeBean = requestScopeBean;
}
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String name = request.getHeader("name");
this.requestScopeBean.setName(name);
}
}
I would like to inject a singleton object dependency to a Spring bean. The catch is that I can't access and modify the class whose object I want to be injected. Let me describe on the example.
So I have my interface, and the implementation of this interface, like the following.
public interface MyServiceProxy {
String BEAN_NAME = "MyServiceProxy";
Data getData(String dataId);
}
public class MyServiceProxyImpl implements MyServiceProxy {
private final MyServiceClient client;
public MyServiceProxyImpl(MyServiceClient client) {
this.client = client;
}
#Override
public Data getData(String dataId) {//...}
Then in my Configuration class, I am creating a bean, but I need to pass it the MyServiceClient object in the constructor, and the catch is that I can't make MyServiceClient a bean because it's from external package and I can't modify it.
#Configuration
public class MyServiceProxyConfiguration {
#Bean(name = MyServiceProxy.BEAN_NAME)
public MyServiceProxy getMyServiceProxy(MyServiceClient client) { // could not autowire client
return new MyServiceProxyImpl(client);
}
}
So what I would like to do, is being able to pass/autowire an argument to getMyServiceProxy bean. Currently IntelliJ is giving me an error Could not autowire client. How can this be achieved?
UPDATE
Would something like the following work? Because IntelliJ is still reporting an "could not autowire" error. So if I created a bean method that returns the client I want injected, and then add #Inject annotation to the method where I want it injected.
public class MyServiceClientBuilder {
private final ClientBuilder builder;
public MyServiceClientBuilder(ClientBuilder builder) {
this.builder = builder;
}
#Bean
public MyServiceClient build() {
return builder.newClient();
}
#Configuration
public class MyServiceProxyConfiguration {
#Inject
#Bean(name = MyServiceProxy.BEAN_NAME)
public MyServiceProxy getMyServiceProxy(MyServiceClient client) { // could not autowire client
return new MyServiceProxyImpl(client);
}
}
You can define MyServiceClient as a separate bean in your configuration file like this:
#Configuration
public class MyServiceProxyConfiguration {
#Bean
public MyServiceClient getMyServiceClient () {
return MyServiceClient.getInstance(); //initiate MyServiceClient
}
#Bean(name = MyServiceProxy.BEAN_NAME)
public MyServiceProxy getMyServiceProxy(MyServiceClient client) {
return new MyServiceProxyImpl(client);
}
}
I have not tested this code, but it should work.
I'm developing a web application with spring. I've had no problem autowiring and using database #Service classes. Now I'm trying to read a global property file and provide the values to all classes that need them. The solution I've come up with so far seem to be overly complicated (too many classes - AppConfig, ServerConfig iface, ElasticServerConfig) for such a trivial task but I could live with it if it worked.
my applicationContext.xml contains
<context:component-scan base-package="my.package" />
AppConfig.java:
package my.package.configuration;
#Configuration
#PropertySource("classpath:application.properties")
public class AppConfig {
}
ServerConfig.java:
public interface ServerConfig {
String getUrl();
String getUser();
String getPassword();
}
ElasticSearchConfig.java:
package my.package.configuration;
#Component(value = "elasticServerConfig")
public class ElasticServerConfig implements ServerConfig {
private static final Logger LOGGER = LogManager.getLogger(ElasticServerConfig.class);
private String url;
private String user;
private String password;
#Autowired
public ElasticServerConfig(final Environment env) {
this.url = env.getProperty("elastic_server.url");
this.user = env.getProperty("elastic_server.user");
this.password = env.getProperty("elastic_server.password");
LOGGER.debug("url=" + url + "; user=" + user + "; password=" + password); // this works!
}
#Override
public final String getUrl() {
return url;
}
#Override
public final String getUser() {
return user;
}
#Override
public final String getPassword() {
return password;
}
}
When the web application boots, the ElasticServerConfig constructor prints out the correct url/user/pwd as read from application.properties. However an instance of ElasticServerConfig is not injected into a Search object:
package my.package.util;
public class Search {
#Autowired
#Qualifier("elasticServerConfig")
private ServerConfig elasticServerConfig;
public final List<Foobar> findByPatternAndLocation() {
if (elasticServerConfig == null) {
LOGGER.error("elasticServerConfig is null!");
}
// and i get a NullPointerException further on
// snip
}
}
You have to register the Search class as a Spring Bean and take it from the Spring context when you want to use it. It's important to get the bean from the spring context. If you create an object of that class with new, Spring has no way to know about that class and mange it's dependencies.
You can get get a bean from the Spring context by #Autowire it somewhere or by accessing an instance of the context and use the getBean method:
#Configuration
#PropertySource("classpath:application.properties")
public class AppConfig {
public static void main(String[] args) {
ApplicationContext ctx = SpringApplication.run(AppConfig.class, args);
ctx.getBean...
}
}
Either use #Component annotation on the class and make sure that the class is in package thats under my.package
or register it in the configuration class
#Configuration
#PropertySource("classpath:application.properties")
public class AppConfig {
#Bean
public Search search(){
return new Search();
}
}
I am trying to find out what is the usability of inter-type declarations in Spring AOP but I am stuck with one problem that makes it a bit useless.
HelloMixin aspect declares that advised services implement HelloService and provides a default implementation HelloServiceImpl.
#Aspect
public class HelloMixin {
#DeclareParents(value = "xxx.xxx.services.*+", defaultImpl = HelloServiceImpl.class)
static HelloService mixin;
}
Then I have two services:
#Service
public class FirstService {
private String name = "First";
public String getName() {
return name;
}
}
#Service
public class SecondService {
private String name = "Second";
public String getName() {
return name;
}
}
New interface:
public interface HelloService {
public void sayHello();
}
Default implementation:
public class HelloServiceImpl implements HelloService {
private String getName() {
return "defaultName";
}
#Override
public void sayHello() {
System.out.println("Hello " + getName());
}
}
Execution:
#Autowired
#Qualifier("firstService")
HelloService firstService;
#Autowired
#Qualifier("secondService")
HelloService secondService;
public String hello() {
firstService.sayHello();
secondService.sayHello();
}
Result:
INFO: Hello defaultName
INFO: Hello defaultName
This concept could be really cool if I had a way to use getName methods from advised objects. Otherwise I do not see any sense to use it if I am not able to write any object dependent logic. Is it possible? In other words I would like to see the result:
INFO: Hello First
INFO: Hello Second
You could do it using #DeclareMixin instead, that allows to use a factory method for creating the delegate.
#Aspect
public class HelloMixin {
#DeclareMixin("xxx.xxx.services.*+")
public HelloService createHelloService(Object target) {
return new HelloServiceImpl(target);
}
}
public class HelloServiceImpl implements HelloService {
private Object target;
public HelloServiceImpl(Object target) {
this.target = target;
}
#Override
public void sayHello() {
System.out.println("Hello " + getNameFromTarget());
}
private String getNameFromTarget() {
// call to this.target.getName()....
}
}
Spring AOP don't support #DeclareMixin annotation, see https://jira.spring.io/browse/SPR-11350 but I added it to JDAL 2.0 in a small independent module jdal-aop, so I encourage you to try it.
When using Spring's based XML configuration, it's easy to decorate multiple implementations of the same interface and specify the order. For instance, a logging service wraps a transactional service which wraps the actual service.
How can I achieve the same using the javax.inject annotations?
You can use #Named together with #Inject to specify which bean to inject.
A simple example with an injected service:
public class ServiceTest {
#Inject
#Named("transactionDecorator")
private Service service;
}
And the corresponding transaction decorator class:
#org.springframework.stereotype.Service("transactionDecorator")
public class ServiceDecoratorTransactionSupport extends ServiceDecorator {
#Inject
#Named("serviceBean")
public ServiceDecoratorTransactionSupport(Service service) {
super(service);
}
}
This exposes your configuration into your code, so I would recommend doing the decorating logic in a #Configuration class and annotate for example the logging service with #Primary. With this approach your test class can look something like this:
public class ServiceTest {
#Inject
private Service service;
And the configuration class:
#Configuration
public class DecoratorConfig {
#Bean
#Primary
public ServiceDecorator serviceDecoratorSecurity() {
return new ServiceDecoratorSecuritySupport(
serviceDecoratorTransactionSupport());
}
#Bean
public ServiceDecorator serviceDecoratorTransactionSupport() {
return new ServiceDecoratorTransactionSupport(serviceBean());
}
#Bean
public Service serviceBean() {
return new ServiceImpl(serviceRepositoryEverythingOkayStub());
}
#Bean
public ServiceRepository serviceRepositoryEverythingOkayStub() {
return new ServiceRepositoryEverythingOkStub();
}
}
My second example doesn't expose any details about which implementation that will be returned, but it depends on several Spring specific classes.
You can also combine the two solutions. For example use Spring's #Primary annotation on a decorator and let Spring inject this decorator into the instance of the given type.
#Service
#Primary
public class ServiceDecoratorSecuritySupport extends ServiceDecorator {
}
This is the sort of thing you typically use AOP for, rather than writing and wrapping implementations manually (not that you can't do that).
For AOP with Guice, you'd want to create a transactional MethodInterceptor and a logging MethodInterceptor, then use bindInterceptor(Matcher, Matcher, MethodInterceptor) to set which types and methods should be intercepted. The first Matcher matches types to intercept, the second matches methods to intercept. Either can be Matchers.any(), match a specific annotation on a type or method (#Transactional, say) or whatever you want. Matching methods are then intercepted and handled automatically. Decorator pattern with a lot less boilerplate, basically.
To do it manually, one way would be:
class ServiceModule extends PrivateModule {
#Override protected void configure() {
bind(Service.class).annotatedWith(Real.class).to(RealService.class);
}
#Provides #Exposed
protected Service provideService(#Real Service service) {
return new LoggingService(new TransactionalService(service));
}
}
#Target(PARAMETER)
#Retention(RUNTIME)
#BindingAnnotation
public #interface Decorate {
Class<?> value();
}
/* see com.google.inject.name.NamedImpl for rest of
the methods DecorateImpl must implement */
public class DecorateImpl implements Decorate, Serializable {
private final Class<?> value;
private DecorateImpl(Class<?> val) {
value = val;
}
public static Decorate get(Class<?> clazz) {
return new DecorateImpl(clazz);
}
public Class<?> value() {
return value;
}
...
...
}
Here is how to use it:
public interface ApService {
String foo(String s);
}
public class ApImpl implements ApService {
private final String name;
#Inject
public ApImpl(#Named("ApImpl.name") String name) {
this.name = name;
}
#Override
public String foo(String s) {
return name + ":" + s;
}
}
First decorator:
public class ApDecorator implements ApService {
private final ApService dcrtd;
private final String name;
#Inject
public ApDecorator(#Decorate(ApDecorator.class) ApService dcrtd,
#Named("ApDecorator.name") String name) {
this.dcrtd = dcrtd;
this.name = name;
}
public String foo(String s) {
return name + ":" + s + ":"+dcrtd.foo(s);
}
}
Second decorator:
public class D2 implements ApService {
private final ApService dcrt;
#Inject
public D2(#Decorate(D2.class) ApService dcrt) {
this.dcrt = dcrt;
}
#Override
public String foo(String s) {
return "D2:" + s + ":" + dcrt.foo(s);
}
}
public class DecoratingTest {
#Test
public void test_decorating_provider() throws Exception {
Injector inj = Guice.createInjector(new DecoratingModule());
ApService mi = inj.getInstance(ApService.class);
assertTrue(mi.foo("z").matches("D2:z:D:z:I:z"));
}
}
The Module:
class DecoratingModule extends AbstractModule {
#Override
protected void configure() {
bindConstant().annotatedWith(Names.named("ApImpl.name")).to("I");
bindConstant().annotatedWith(Names.named("ApDecorator.name")).to("D");
bind(ApService.class).
annotatedWith(DecorateImpl.get(ApDecorator.class)).
to(AnImpl.class);
bind(ApService.class).
annotatedWith(DecorateImpl.get(D2.class)).
to(ApDecorator.class);
bind(ApService.class).to(D2.class);
}
}
If bindings configuration looks ugly, you can create Builder/DSL that looks nice.
The drawback is that (comparing with manual chain building) you can not chain the same module twice (i.e. D2->D2->D1->Impl) and the boilerplate in the constructor params.