I kbow Proxy object extends the target class and overrides non final methods. My question is, when the proxy object overrides target method, what extra code it adds to target method that makes advice to get called? And how proxy knows when to call an advice,before, after etc?
What you are asking is a bit too broad since the code used is quite complex.
I'm not sure why do you want to know the exact implementation details but as starting point you should check how Spring AOP works:
https://docs.spring.io/spring/docs/5.1.x/spring-framework-reference/core.html#aop
Spring implements proxying by using CGLIB or the JDK depending the situation (i.e.: if you implement your beans using interfaces, Spring will try to use the JDK).
You can check the Proxying mechanisms here: https://docs.spring.io/spring/docs/5.1.x/spring-framework-reference/core.html#aop-proxying
From there you can search for the libraries and check the code used for proxying.
I hope this serves you as a starting point for your reasearch.
Related
I have been working with Spring Data JPA repository in my project for some time and I know the below points:
In the repository interfaces, we can add the methods like findByCustomerNameAndPhone() (assuming customerName and phone are fields in the domain object).
Then, Spring provides the implementation by implementing the above repository interface methods at runtime (during the application run).
I am interested on how this has been coded and I have looked at the Spring JPA source code & APIs, but I could not find answers to the questions below:
How is the repository implementation class generated at runtime & methods being implemented and injected?
Does Spring Data JPA use CGlib or any bytecode manipulation libraries to implement the methods and inject dynamically?
Could you please help with the above queries and also provide any supported documentation ?
First of all, there's no code generation going on, which means: no CGLib, no byte-code generation at all. The fundamental approach is that a JDK proxy instance is created programmatically using Spring's ProxyFactory API to back the interface and a MethodInterceptor intercepts all calls to the instance and routes the method into the appropriate places:
If the repository has been initialized with a custom implementation part (see that part of the reference documentation for details), and the method invoked is implemented in that class, the call is routed there.
If the method is a query method (see DefaultRepositoryInformation for how that is determined), the store specific query execution mechanism kicks in and executes the query determined to be executed for that method at startup. For that a resolution mechanism is in place that tries to identify explicitly declared queries in various places (using #Query on the method, JPA named queries) eventually falling back to query derivation from the method name. For the query mechanism detection, see JpaQueryLookupStrategy. The parsing logic for the query derivation can be found in PartTree. The store specific translation into an actual query can be seen e.g. in JpaQueryCreator.
If none of the above apply the method executed has to be one implemented by a store-specific repository base class (SimpleJpaRepository in case of JPA) and the call is routed into an instance of that.
The method interceptor implementing that routing logic is QueryExecutorMethodInterceptor, the high level routing logic can be found here.
The creation of those proxies is encapsulated into a standard Java based Factory pattern implementation. The high-level proxy creation can be found in RepositoryFactorySupport. The store-specific implementations then add the necessary infrastructure components so that for JPA you can go ahead and just write code like this:
EntityManager em = … // obtain an EntityManager
JpaRepositoryFactory factory = new JpaRepositoryFactory(em);
UserRepository repository = factory.getRepository(UserRepository.class);
The reason I mention that explicitly is that it should become clear that, in its core, nothing of that code requires a Spring container to run in the first place. It needs Spring as a library on the classpath (because we prefer to not reinvent the wheel), but is container agnostic in general.
To ease the integration with DI containers we've of course then built integration with Spring Java configuration, an XML namespace, but also a CDI extension, so that Spring Data can be used in plain CDI scenarios.
I'm providing a Spring RestController as a part of a library. Currently I have reusable jaxrs services, but I need to make Spring Boot alternatives. One RestController for example has 2 dependencies: one is a service that I could see being a bean and the other a String property.
I'm wondering what is the idiomatic way to expect to get those dependencies from users consuming the library. I had a few ideas about how it might happen, but wasn't sure what was the right or at least best practice way to do it.
Should users construct the RestController manually using the constructor (not using dependency injection)? I actually couldn't even figure out how to do this such that the Spring Boot Application knew about it and didn't see it in guides, so I was assuming this isn't the normal way to provide RestControllers. I only wondered if this was the right way to go as dependency injection being used for a third party library class's dependencies seems like it could be hard to manage.
Should both be beans, with the String property being a named bean? I have this one working, but I'm wondering if consumers of the library having to provide beans that the library's RestController expects is tricky or a bad practice.
Should the simple service be a bean and the String injected via #Value?
Is there some alternative or better way?
I have read that dependency injection is good for testing, in that a class can be tested without its dependencies, but the question comes to my mind if Class A depends on Class B or C or any class, testing Class A independent of some class is yielding a test result of zero, not a failed or past test.
Class A was created to do something and if it is not fed anything whether using new key word or setting up the extra files in Spring, Class A won't do any work.
About the idea of making code modular, readable and maintainable: so business classes became cleaner, but all we did was shift confusion from dirty Java business classes to convoluted XML files and having to delete interfaces used to inject to our loosened objects.
In short, it seems we have to make edits and changes to a file somewhere,right?
Please feel free to put me in my place if my understanding is lacking, just a little irritated with learning Spring because I see the same amount of work just rearranged.
Dependency injection is good for unit testing because you can individually test each method without that method depending on anything else. That way each unit test can test exactly one method.
I would say that if the xml is what’s annoying you check out Spring boot. It’s based on a java configuration so no xml and it simplifies a lot of configuration for you based on your class path. When I first started spring I found the xml very daunting coming from a java background but the annotation based configuration and the auto configuring done by spring boot is extremely helpful for quickly getting applications working.
IMO biggest advantage of using the spring is dependency injection which makes your life easy. For example if you would like to create a new service with three dependencies, then you can create a class very easily using Spring. But without spring, you will end up writing different factory methods which will return you the instances you are looking for. This makes your code very verbose with static method calls. You may want to take a look at the code repositories before spring era.
Again if you would like to use Spring or not is your personal call based on project complexity. But it's other features/advantages cant be overlooked.
And XML files or Java configs are the ways of achieving spring configuration - where you would like to add your business logic is personal flavour. Only thing is you should be consistent all across your project.
I would suggest that you read Martin Fowler's great article on Inversion of Control and Dependency Injection to gain a better understanding of why frameworks like Spring can be really useful to solve a well known set of common dependency injection problems when writing software.
As others have mentioned, there is no obligation to use Spring; and whatever you can do with Spring, you can probably do it by other means like abstract factories, factory methods, or service locators.
If your project is small enough, then you probably wouldn't mind solving the dependency injection issues on your own using some design patterns like those mentioned above. However, depending on the size of your project, many would prefer to use a framework or a library that already packs a bunch of solutions to these recurrent head scratchers.
In regards to the advantages of dependency injection frameworks when doing unit testing is the idea that you don't need to test the dependencies of your class, but only your class.
For example, most likely your application has a layered design. It is very common to have a data access class or a repository that you use to retrieve data from a datasource. Logically, you also have a class where you use that DAO.
Evidently, you already wrote unit testing for your DAO, and therefore, when you're testing your business class (where the DAO is being used) you don't care about testing your DAO again.
Fortunately, since Spring requires some form of dependency injection for your DAO, this means your class must provide a constructor or a setter method through which we can inject that DAO into our business class, right?
Well, then during unit testing of your business class, you can conveniently use those injection points to inject your own fake DAO (i.e. a mock object). That way, you can focus on the testing of your business class and forget about retesting the DAO again.
Now compare this idea with other solutions you may have done on your own:
You inject the dependency directly by instantiating the DAO within your business class.
You use a static factory method within your code to gain access to the DAO.
You use a static method from a service locator within your code to gain access to the DAO.
None of these solutions would make your code easy to test because there is no simple manner to get in the way of choosing exactly what dependency I want injected into my business class while testing it (e.g. how do you change the static factory method to use a fake DAO for testing purposes?).
So, in Spring, using XML configuration or annotations, you can easily have different dependencies being injected into your service object based on a number of conditions. For example, you may have some configurations for testing that evidently would be different than those used in production. And if you have a staging environment, you may even have different XML configurations of dependencies for your application depending on whether it is running in production or integration environments.
This pluggability of dependencies is the key winning factor here in my opinion.
So, as I was saying, my suggestion to you is that you first expand your understanding of what problems Spring core (and in general all dependency injection frameworks) is trying to solve and why it matters, and that will give you a broader perspective and understanding of these problems in a way that you could to determine when it is a good idea to use Spring and when it is not.
I want to write an RMI library in/for Ceylon (since I have not found one so far).
The first thing I need is a proxy. In Java I used something like
Proxy.newProxyInstance(classLoader, interfaces, handler);
1. Is there something equivalent in Ceylon? (haven't found something)
Attempting to write something like this my own, I came across this solution for the JVM using byte code manipulation.
Nifty and exactly what I want.
Notice, that this can even produce a proxy for a class, not only for interface like in Java. In Ceylon this is should be legit, since there are no fields and we can simulate the whole class with method calls.
2. If creating proxies for classes is a no-go just tell me.
Also, what is the Ceylon intuition/future about proxies? Shall there be (no) proxies?
In a future with proxies we have one major problem:
In Ceylon we have the default keyword, without it a method can not be refined/overwritten. This also results in final methods for the compiled Java output classes. Thereby (not even) the byte code manipulation can overwrite those and redirect them to an invocation handler/interceptor.
3. How do we deal with this?
I assume not at all? I totally get the idea of disallowing the refinement of methods and the default/final keywords, but this obstructs RMI/proxies for classes.
4. Are proxies for classes a bad idea?
And yes, there are so much more questions I am currently thinking about and investigating on: JS implementation, interfaces and default methods, etc
These points seem to be the most relevant at the moment, so let's start here.
You could try using this module I wrote:
https://github.com/gavinking/ceylon.proxy
Alternatively, if you're only targeting the JVM, you could just use Java's Proxy directly.
During further research I found:
1. Proxies are currently part of the Ceylon 1.4 milestone (issues regarding proxies).
3. Enabling EE mode for the ceylon compiler, removes the final keyword.
From this point on the solution I found works like intended and is exactly the same as the one provided by Gavin.
Diving deeper into Spring AOP I already understood that Spring Framework chooses a proxy-based strategy for weaving in aspects. I read that these Proxies are created at runtime and just in time, i.e. "lazy".
Now the following question came up to me: Which scope does such a proxy object have, considering a web appliaction? Is there a way to find out?
I'm looking forward to your answers!
Proxies are usually created by a BeanPostprocessor (in AbstractAutoProxyCreator hirearchy) so them have the same scope as the target bean.
If you create proxies by other ways, like using a ProxyFactoryBean you can change the scope, but in general isn't a good idea.