A Play project (Scala or Java, I use Scala here) created with activator starts with examples like:
class MyController #Inject() {...}
There are several such components that one can inject by default, e.g. Environment, and one of them is Database:
class MyController #Inject()(db: Database) {...}
It manages to read my conf and create a corresponding Database object that I can use in this controller - which I am unable to do otherwise without copying the db configuration.
But is it the right place to do so? Most of the controller will not use the database, so why not use a kind of "SqlHandler" that does all the database-related stuff. I though of something like
#Singleton
class SqlHandler #Inject()(db: Database) {
def select() = {...db...}
def insert() = {...db...}
}
and then call it like
class MyController #Inject() {
def mySqlAction = Action {
SqlHandler.select()
}
}
Is it a good idea? Should I even use injection? And how do I use this singleton in the rest of my app then? (at the moment my SqlHandler is an object since its methods are static).
Yes, It's good practice to place domain logic in other Module like Service, SqlHandler not in controller.
I place custom action with authenticate and filter, error handling and manipulating result code in Controller
You can inject SqlHanlder to Controller.
class MyController #Inject()(handler: SqlHandler)
Related
Suppose I want to use a service in a POJO class, like an implementation of some sort, can I just pass this service as a parameter to this POJO? Or would that be bad practice?
#Service
public class MyService {
// Inject AnotherService in this service
public MyService(AnotherService anotherService) {
// Now pass that service in a POJO
SomeImplementation impl = new SomeImplementation(anotherService);
}
}
public class SomeImplementation {
public SomeImplementation(AnotherService anotherService) {
// start using the AnotherService here...
}
}
For this example I used Java and Spring, but this question applies to all languages with dependency injection.
I would say that it's just not making use of the framework you're operating within. That's exactly what DI is for: letting the container handle the components and their relations (eg. if you inject sth multiple times, DI helps you avoid multiple instantiations).
Now, in your case, you can use the #Configurable annotation, which adds a POJO component to the Spring context, and so lets you inject stuff into it.
I'm new to Spring Boot, so bare me with my basic question here.
I want to build a generic #Service class that has well defined methods that don't even need to be overwritten.
The only thing this class needs is to adjust its attributes based on which Controller method was called. Basically, this class works as a Job handler that needs to adjust some parameters so its methods can perform what they're supposed to compute. The job will always have the same workflow, calling the methods in the same order, but it will obtain different results depending on the parameters/attributes it receives, which, as I said before, are defined by the controller methods.
The only attribute it has beside the ones that adjust the job's workflow is an autowired #Repository object that will save the results of the job in a database.
Maybe I could simply instantiate an Job Handler object and call a constructor with the paramaters I need for the job, but I don't know what is the "Spring way" of doing this, considering how Spring works with dependency injection and I need a #Repository object embbeded into the Job Handler service.
I would really appreciate if anyone could write a sample code/example so I could understand how this can be done with Spring Boot so I don't have to duplicate code or Service Classes.
The Spring way for this case would be to create a Bean of your JobHandler, where you inject the necessary dependencies, like your Repository:
#Configuration
class MyConfiguration {
#Bean
MyJobHandler myJobHandler(MyRepository myRepository) {
return new MyJobHandler (myrepository);
}
}
Alternatively, if you do not want a configuration class, you could declare your JobHandler as a Component and inject the repository in the constructor:
#Component
class MyJobHandler {
private MyRepository myRepository;
public MyJobHandler myJobHandler(MyRepository myRepository) {
this.myRepository = myRepository;
}
}
I got interested in how Spring's #Transactional works internally, but everywhere I read about it there's a concept of proxy. Proxies are supposed to be autowired in place of real bean and "decorate" base method with additional transaction handling methods.
The theory is quite clear to me and makes perfect sense so I tried to check how it works in action.
I created a Spring Boot application with a basic controller and service layers and marked one method with #Transactional annotation. Service looks like this:
public class TestService implements ITestService {
#PersistenceContext
EntityManager entityManager;
#Transactional
public void doSomething() {
System.out.println("Service...");
entityManager.persist(new TestEntity("XYZ"));
}}
Controller calls the service:
public class TestController {
#Autowired
ITestService testService;
#PostMapping("/doSomething")
public ResponseEntity addHero() {
testService.doSomething();
System.out.println(Proxy.isProxyClass(testService.getClass()));
System.out.println(testService);
return new ResponseEntity(HttpStatus.OK);
}}
The whole thing works, new entity is persisted to the DB but the whole point of my concern is the output:
Service...
false
com.example.demo.TestService#7fb48179
It seems that the service class was injected explicitly instead of proxy class. Not only "isProxy" returns false, but also the class output ("com.example.demo.TestService#7fb48179") suggests its not a proxy.
Could you please help me out with that? Why wasn't the proxy injected, and how does it even work without proxy? Is there any way I can "force" it to be proxied, and if so - why the proxy is not injected by default by Spring ?
There's not much to be added, this is a really simple app. Application properties are nothing fancy either :
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=superSecretPassword
spring.datasource.url=jdbc:mysql://localhost:3306/heroes?serverTimezone=UTC
spring.jpa.hibernate.ddl-auto=create-drop
Thank you in advance!
Your understanding is correct, but your test is flawed:
When the spring docs say "proxy", they are referring to the pattern, not a particular implementation. Spring supports various strategies for creating proxy objects. One of these is the java.lang.reflect.Proxy you tested for, but by default spring uses a more advanced technique that generates a new class definition at runtime that subclasses the actual implementation class of the service (and overrides all methods to apply transaction advice). You can see this in action by checking testService.getClass(), which will refer to that generated class, or by halting execution in a debugger, and inspecting the fields of targetService.
The reason that toString() refers to the original object is that the proxy implements toString() by delegating to its target object, which uses its class name to build the String.
I am doing unit tests for a rest controller, which is only a small part of a bigger application.
Ideally I would like to use a mocking framework to ensure that the test are unitary. I would mock the manager and the dao.
However that would require to have different configurations for the rest controller class that make him use a different manager depending if we are in test context or in application context.
The mocks are defined in context-test.xml.
This is what I have done so far :
Test RestController
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(locations = "classpath:/META-INF/spring/context-test.xml")
#WebIntegrationTest
public class MyRestControllerTest extends AbstractTransactionnalTest {
#Autowired
private IManager manager;
#Test
// my unit tests
}
RestController
#RestController
#SpringApplicationConfiguration(locations = {"classpath:/META-INF/spring/context-test.xml",
"classpath:/META-INF/spring/context-application.xml"})
#RequestMapping("/me")
class MyRestController {
#Autowired
private IManager manager;
// Content of my controller
}
The main issue with my solution so far :
- I dont know how to tell the RestController wich context to use. (I only want to use one context at a time)
Is there a better solution to do this ?
I agree with #chrylis. The problem here I think may be your class design.
If your MyRestController class is dependent on knowing which context is passed in, seems like this would be a Spring/DI anti-pattern. The whole point of DI is that the class "passively" handles the context with correct behavior in the first place.
Any injected objects should simply be created/handled correctly by the injecting context.
You could try adding a setManager() method, this would allow you to set the manager in your controller to a 'mocked' manager.
I'm trying to change some legacy code to use DI with Spring framework. I have a concrete case for which I'm wondering which is the most proper way to implement it.
It is a java desktop application. There is a DataManager interface used to query / change data from the data store. Currently there is only one implementation using a XML file for store, but in the future it is possible to add SQL implementation. Also for unit testing I may need to mock it.
Currently every peace of code that needs the data manager retrieves it by using a factory. Here is the source code of the factory:
public class DataManagerFactory
{
private static DataManagerIfc dataManager;
public static DataManagerIfc getInstance()
{
// Let assume synchronization is not needed
if(dataManager == null)
dataManager = new XMLFileDataManager();
return dataManager;
}
}
Now I see 3 ways to change the application to use DI and Spring.
I. Inject the dependency only in the factory and do not change any other code.
Here is the new code:
public class DataManagerFactory
{
private DataManagerIfc dataManager;
public DataManagerFactory(DataManagerIfc dataManager)
{
this.dataManager = dataManager;
}
public DataManagerIfc getDataManager()
{
return dataManager;
}
public static DataManagerIfc getInstance()
{
return getFactoryInstance().getDataManager();
}
public static DataManagerFactory getFactoryInstance()
{
ApplicationContext context =
new ClassPathXmlApplicationContext(new String[] {"com/mypackage/SpringConfig.xml"});
return context.getBean(DataManagerFactory.class);
}
}
And the XML with the bean description:
<bean id="dataManagerFactory"
class="com.mypackage.DataManagerFactory">
<constructor-arg ref="xmlFileDataManager"/>
</bean>
<bean id="xmlFileDataManager"
class="com.mypackage.datamanagers.xmlfiledatamanager.XMLFileDataManager">
</bean>
II. Change every class that is using the data manager so it takes it through the constructor and store it as a class variable. Make Spring bean definitions only for the "root" classes from where the chain of creation starts.
III. Same as II. but for every class that is using the data manager create a Spring bean definition and instantiate every such class by using the Spring Ioc container.
As I'm new to the DI concept, I will appreciate every advice what will be the correct and "best practice" solution.
Many thanks in advance.
Use option 3.
The first option keeps your code untestable. You won't be able to easily mock the static factory method so that it returns a mock DataManager.
The second option will force you to have the root classes know all the dependencies of all the non-root classes in order to make the code testable.
The third option really uses dependency injection, where each bean only know about its direct dependencies, and is injected by the DI container.
Well... why did you write the factory in the first place? Spring is not intended to make you change how you write code (not just to suit Spring that is), so keeping the factory is correct as it uses well-known pattern. Injecting the dependency into the factory will retain that behaviour.
Option 3 is the correct route to take. By using such a configuration you can usefully take components of your configuration and use them in new configurations, and everything will work as expected.
As a rule of thumb, I would expect one call to Spring to instantiate the application context and get the top-level bean. I wouldn't expect to make repeated calls to the Spring framework to get multiple beans. Everything should be injected at the correct level to reflect responsibilities etc.
Beware (since you're new to this) that you don't plumb in your data manager into every class available! This is quite a common mistake to make, and if you've not abstracted out and centralised responsibilities sufficiently, you'll find you're configuring classes with lots of managers. When you see you're doing this it's a good time to step back and look at your abstractions and componentisation.