aspectj check broken layer access in spring boot - spring-boot

I try to use aspectj for checking whether the layers of the architecture are broken, e.g. the access from controller to repository without using a service between
Now this is marking every method call to a autowired annotated within de.fhb.controller.
but how can i then limit that to Repositories for example?
The package structure looks like this:
de.fhb.controller
de.fhb.service
de.fhb.entity and and so on.
my aspect looks like this
#Aspect
public class Layer {
#DeclareError("within(de.fhb.controller..*) && #annotation(org.springframework.beans.factory.annotation.Autowired) " )
private static final String typeWarning = "You try to access through many layers";
}
the repository:
#Repository
public interface BoxRepository extends JpaRepository<Box, Long>{
public List findByPrio(long prio);
}
and the controller that should be checked by aspects:
#RequestMapping("/box")
#Controller
public class BoxController {
#Autowired
private BoxRepository boxRepository; // negative example
#Autowired
private BoxService boxService;
#RequestMapping(value = "/")
public String list(Model model) {
List boxes = boxRepository.findAll(); // negativ example
model.addAttribute("boxes", boxes);
return "box/list";
}
for further look: repository at github

Your pointcut
within(de.fhb.controller..*) &&
execution(de.fhb.repository.BoxRepository *(..))
means in prose: Intercept any method in package de.fhb.controller or its sub-packages which has a return type of de.fhb.repository.BoxRepository, but in your code is no such method. So you will never see a compiler error.
;-)
Updated answer after question update:
You need to intercept calls to methods of types with a #Repository annotation:
within(de.fhb.controller..*) &&
call(* (#org.springframework.stereotype.Repository *).*(..))
But in order to do that you need to switch from Spring AOP to full-blown AspectJ with compile-time weaving, i.e. you need to use the AspectJ compiler Ajc to compile and weave your aspect. The reason is that Spring AOP does not support the call() pointcut, but this is what you need. An execution() pointcut will not help you here, but that is the only one supported by a proxy-based "AOP lite" framework like Spring AOP. You just need to weave this one aspect with AspectJ, the other aspects can still use Spring AOP. But then need to take care about AspectJ not picking up your other aspects.

Related

Not Matching this type name

I have many aspect class in com.aop.aspect package. What I want to do is to work all class except for one class named for com.aop.dao.MyDemoLoggingAspect
When I run the app, there is an error appeared on the console.
java.lang.IllegalArgumentException: warning no match for this type name: com.aop.dao.MyDemoLoggingAspect [Xlint:invalidAbsoluteTypeName]
Here is my aspect class
#Aspect
public class LuvAopExpressionsOrder {
#Pointcut("execution(* com.aop.dao.*.*(..))")
public void forDaoPackage() {}
// create pointcut for getter methods
#Pointcut("execution(* com.aop.dao.*.get*(..))")
public void getter() {}
// create pointcut for setter methods
#Pointcut("execution(* com.aop.dao.*.set*(..))")
public void setter() {}
// create pointcut for setter methods
#Pointcut("!execution(* com.aop.dao.MyDemoLoggingAspect.*(..))")
public void excludeMyDemoLoggingAspect() {}
// create pointcut: include package ... exclude getter/setter and MyDemoLoggingAspect
#Pointcut("forDaoPackage() && !(getter() || setter()) && excludeMyDemoLoggingAspect() ")
public void forDaoPackageNoGetterSetter() {}
}
If you use Spring AOP you don't need to be afraid that one aspect will intercept methods from another because Spring does not support that, as is documented in chapter 5.4.2. Declaring an Aspect. Scroll down a bit and look for this info box:
Advising aspects with other aspects?
In Spring AOP, aspects themselves cannot be the targets of advice from other aspects. The #Aspect annotation on a class marks it as an aspect and, hence, excludes it from auto-proxying.
So basically your issue is a non-issue.
If however you use AspectJ via LTW you are subject to no such limitations and thus have to be careful to exclude other aspects which would normally be intercepted due to matching pointcuts. I recommend to put aspects in packages which are easy to exclude, otherwise you have to do it class name by class name. Use pointcuts like these, depending on your situation:
!within(com.aop.dao.MyDemoLoggingAspect)
!within(com.acme.aop..*)
!within(com.acme..*Aspect)

Is it possible to add PointCut to ModelAndView method?

I tried to use PointCut to perform some post action after ModelAndView.setViewName, but it seems that it never triggers:
#Aspect
#Component
public class TestAspect {
private Logger logger = LoggerFactory.getLogger(this.getClass());
#Pointcut("execution(* org.springframework.web.servlet.ModelAndView.*(..))")
public void testPointCut() {
}
#After("testPointCut()")
public void afterPointCut(JoinPoint joinPoint) {
logger.debug("afterPointCut");
}
}
If I change the execution part to some class of my own, this point cut works.
So what is the correct way to add PointCut to ModelAndView?
I am not a Spring user, but what I know about Spring AOP is that you can only apply it to Spring components. The class ModelAndView is not derived from any Spring core component class or annotated by anything making it such, it is a simple POJO. As such you cannot target it by Spring AOP pointcuts. You should rather target something within the reach of Spring AOP.
The alternative would be to unpack the big gun and use full AspectJ LTW (load-time weaving) which is not limited to Spring components.

Where should #Service annotation be kept? Interface or Implementation?

I'm developing an application using Spring. I need to use the #Service annotation. I have ServiceI and ServiceImpl such that ServiceImpl implements ServiceI. I'm confused here as to where should I keep the #Service annotation.
Should I annotate the interface or the implementation with #Service? What are the differences between these two approaches?
I never put #Component (or #Service, ...) at an interface, because this make the interface useless. Let me explain why.
claim 1: If you have an interface then you want to use that interface for the injection point type.
claim 2: The purpose of an interface is that it define a contract that can been implemented by several implementations. On the other side you have your injection point (#Autowired). Having just one interface and only one class that implement it, is (IMHO) useless, and violates YAGNI.
fact: When you put:
#Component (or #Service, ...) at an interface,
have multiple classes that implements it,
at least two classes become Spring Beans, and
have an injection point that use the interface for type based injection,
then you will get and NoUniqueBeanDefinitionException
(or you have a very special configurations setup, with Environment, Profiles or Qualifiers ...)
Conclusion: If you use #Component (or #Service, ...) at an interface then you must violate at least one of the two clains. Therefore I think it is not useful (except some rare scenarios) to put #Component at interface level.
Spring-Data-JPA Repository interfaces are something complete different
Basically annotations like #Service, #Repository, #Component, etc. they all serve the same purpose:
auto-detection when using annotation-based configuration and classpath
scanning.
From my experience I am always using #Service annotation on the interfaces or abstract classes and annotations like #Component and #Repository for their implementation. #Component annotation I am using on those classes which serves basic purposes, simple Spring beans, nothing more. #Repository annotation I am using in the DAO layer, for e.g. if I have to communicate to the database, have some transactions, etc.
So I would suggest to annotate your interface with the #Service and other layers depending on the functionality.
I used #Component, #Service, #Controller and #Repository annotations only on the implementation classes and not on the interface. But #Autowired annotation with Interfaces still worked for me. If there's only one implementation of your interface Spring component scan automatically finds it with just #Autowired annotation. In case you have multiple implementations, you will need to use the #Qualifier annotation along with #Autowired to inject the correct implementation at the injection point.
1. #Service on Interfaces
#Service
public interface AuthenticationService {
boolean authenticate(String username, String password);
}
Normally, that's fine, but there's a drawback. By putting Spring's #Service on interfaces, we create an extra dependency and couple our interfaces with an outside library.
Next, to test the autodetection of our new service beans, let's create an implementation of our AuthenticationService:
public class InMemoryAuthenticationService implements AuthenticationService {
#Override
public boolean authenticate(String username, String password) {
//...
}
}
We should pay attention that our new implementation, InMemoryAuthenticationService, doesn't have the #Service annotation on it. We left #Service only on the interface, AuthenticationService.
So, let's run our Spring context with the help of a basic Spring Boot setup:
#SpringBootApplication
public class AuthApplication {
#Autowired
private AuthenticationService authService;
public static void main(String[] args) {
SpringApplication.run(AuthApplication.class, args);
}
}
When we run our app, we may get the infamous NoSuchBeanDefinitionException, and the Spring context fails to start.
Therefore, placing #Service on interfaces isn't enough for the auto-detection of Spring components.
2. #Service on Abstract Classes
Using the #Service annotation on abstract classes isn't common.
We'll start by defining an abstract class from scratch and putting the #Service annotation on it:
#Service
public abstract class AbstractAuthenticationService {
public boolean authenticate(String username, String password) {
return false;
}
}
Next, we extend AbstractAuthenticationService to create a concrete implementation without annotating it:
public class LdapAuthenticationService extends AbstractAuthenticationService {
#Override
public boolean authenticate(String username, String password) {
//...
}
}
Accordingly, we also update our AuthApplication, to inject the new service class:
#SpringBootApplication
public class AuthApplication {
#Autowired
private AbstractAuthenticationService authService;
public static void main(String[] args) {
SpringApplication.run(AuthApplication.class, args);
}
}
After we run our AuthApplication, the Spring context doesn't start. It ends up with the same NoSuchBeanDefinitionException exception again.
So, using #Service annotation on abstract classes doesn't have any effect in Spring.
3. #Service on Concrete Classes
Contrary to what we've seen above, it's quite a common practice to annotate the implementation classes instead of abstract classes or interfaces.
In this way, our goal is mostly to tell Spring this class is going to be a #Component and mark it with a special stereotype, which is #Service in our case.
Therefore, Spring will autodetect those classes from the classpath and automatically define them as managed beans.
So, let's put #Service on our concrete service classes this time around. We'll have one class that implements our interface and a second that extends the abstract class that we defined previously:
#Service
public class InMemoryAuthenticationService implements AuthenticationService {
#Override
public boolean authenticate(String username, String password) {
//...
}
}
#Service
public class LdapAuthenticationService extends AbstractAuthenticationService {
#Override
public boolean authenticate(String username, String password) {
//...
}
}
We should take notice here that our AbstractAuthenticationService doesn't implement the AuthenticationService here. Hence, we can test them independently.
Finally, we add both of our service classes into the AuthApplication and give it a try:
#SpringBootApplication
public class AuthApplication {
#Autowired
private AuthenticationService inMemoryAuthService;
#Autowired
private AbstractAuthenticationService ldapAuthService;
public static void main(String[] args) {
SpringApplication.run(AuthApplication.class, args);
}
}
Our final test gives us a successful result, and the Spring context boots up with no exceptions. Both of the services are automatically registered as beans.
You might have a look at this page for the other explanations.
Pros of putting annotation on #Service is that it gives a hint that it is a service. I don't know if any implementing class will by default inherit this annoation.
Con side is that you are coupling your interface with a specific framework i.e. Spring, by using spring specific annotation.
As interfaces are supposed to be decoupled from implementation, I would not suggest using any framework specific Annotations or object part of your interface.
I would put #Service on your class but put the name of the interface as a parameter to the annotation e.g.
interface ServiceOne {}
#Service("ServiceOne")
class ServiceOneImpl implements ServiceOne{}
By doing that you get all the benefits and can still inject the interface but get the class
#Autowired
private ServiceOne serviceOne;
So your interface is not tied to spring framework and you can change the class at any time and not have to update all your injection points.
So if I wanted to change the implementation class I could just annotate the new class and remove from the first but that's all that is required to be changed. If you inject the class you could have a lot of work when ever you want to change the impl class.
One benefit of spring is to easily switch Service (or other) implementation.
For this, you need to annotate on the interface and declare variable like this :
#Autowired
private MyInterface myVariable;
and not :
#Autowired
private MyClassImplementationWhichImplementsMyInterface myVariable;
Like the first case, you can activate which implementation to inject from the moment it is unique (only one class implements the interface).
In the second case, you need to refactor all your code (the new class implementation has another name).
As a consequence, the annotation needs to be on the interface as much as possible. Furthermore, JDK proxies are well suited for this : they are created and instantiated at application startup because runtime type is known by advance, contrary to CGlib proxies.
interface MyService {}
#Service
class MyServiceImpl implements MyService{}
#Autowired
private MyService myService;
My testing result on spring-boot 2.7.4 is:
Adding #Service ONLY to interface doesn't create spring bean named MyService. It will error on Autowired.
#Service will need to be added to implementation class to create bean com.*.service.impl.MyServiceImpl $$EnhancerBySpringCGLIB$$9140ae19 Spring will wire it to private MyService myService;
There are 5 annotations which could be used for making spring beans. List in below of answers.
Do you really need an interface? If you are going to have one implementation for each service interface, just avoid it, use only class. Of course, if you don't have RMI or when interface proxy is required.
#Repository - use for injecting your dao layer classes.
#Service - use for injecting your service layer classes. In service layer also you might need to use #Transactional annotation for db transaction management.
#Controller - use for your frontend layer controllers, such as JSF managed beans injecting as spring beans.
#RestController - use for spring rest controllers, this would help you to avoid every time to put #ResponseBody and #RequestBody annotations in your rest methods.
#Component - use it in any other case when you need to Inject spring bean which is not controller, service, or dao class
To put it simply:
#Service is a Stereotype annotation for the service layer.
#Repos­itory is a Stereotype annotation for the persis­tence layer.
#Component is a generic stereotype annotation used to tell Spring to create an instance of the object in the Appl­ication Context. It's possible to
define any name for the instance, the default is the class name as camel case.

Spring beginner questions about annotations and thread safety

I am not sure if I am allowed to ask more than one question in a post, but here it is,
For example I have the following,
Controllers
#Controller
public class FooController{
#Autowired
private FooService fooService;
#RequestMapping(value="/foo", method=RequestMethod.POST)
public #ResponseBody foo(#RequestBody FooRequest request){
}
}
#Controller
public class BarController{
#Autowired
private FooService fooService;
#RequestMapping(value="/bar", method=RequestMethod.POST)
public #ResponseBody bar(#RequestBody FooRequest request){
}
}
Service
public class FooService{
private Foo foo;
public Foo getFoo() {
return foo;
}
public void setFoo(Foo foo) {
this.foo = foo;
}
public String doFoo(String str){
return foo.doFoo(str);
}
}
class to do the job
public class Foo{
public String doFoo(String str){
return (str + " is foo");
}
}
create beans using dependency injection
<context:annotation-config/>
<bean id="fooService" class="com.myapp.service.FooService">
<property name="foo" ref="foo"></property>
</bean>
<bean id="foo" class="com.myapp.foo.Foo">
</bean>
My questions are:
I did not use #service annotation at class FooService, should I use it, and why?
Is this configuration thread-safe or not, and why (how is it achieved if it is thread-safe)?
Where can I find a tutorial about the layers (dao layers, service layer ...) used in Spring design and the purpose of such a design?
You don't have to use annotations if you declare your beans in xml-config, as you did.
It is. Each bean, although a singleton, is stateless. So no concurrent modifications can occur.
For example in wikipedia. It's not spring-specific. Look for articles about three-tier architecture
Using it would simply avoid the need for declaring the bean using XML. You chose to use annotations for your other beans. I would thus also use annotations for this one.
Yes, it is, because Spring makes sure everything is properly wired up and initialized, with a synchronization barrier, before serving any request
This is a very broad question. Layering is useful for separation of concerns, testability, ability to demarcate transactions declaratively, etc.
#Repository, #Service, or #Controller (sub-annotations of #Components) are used to mark specific classes, so they can be considered more-or-less as metadata. However, there are some features of the Spring framework that can take advantage of these. One of them is automatic component scanning (a given java package will be searched for classes with the above annotations and these classes can be used as Spring beans, as if they were declared in XML). To enable this, you should put this into your spring context:
<context:component-scan base-package="my.service.package"/>
More on this can be found here: http://static.springsource.org/spring/docs/3.0.x/reference/beans.html#beans-classpath-scanning
Another use-case is for AOP. You can create annotation-aware pointcuts by which you can select say all your repository classes.
The Spring beans in context are brought up one by one, so there is no chance of concurrency kicking in. However, there can be circular dependencies between beans and Spring may or may not resolve this properly.
For both DAO and service stuff, the current Spring 3 documentation provides many examples and probably the best source for learning: http://static.springsource.org/spring/docs/3.0.x/reference/index.html If you'd like to have an all-round knowledge I'd recommend trying out JdbcTemplate, Rowmappers and an ORM based configuration with Hibernate.

Use Spring #Transactional in Scala

We have a mixed Java and Scala project, which uses Spring transaction management. We are using the Spring aspects to weave the files with #Transactional annotated methods.
The problem is, that the Scala classes aren't woven with the Spring transaction aspects. How can I configure Spring to regard the transaction in Scala?
Spring needs your transaction boundary to begin with Spring-managed beans, so this precludes #Transactional Scala classes.
It sounds like the simple solution is to make service facades which are #Transactional Java classes instantiated as Spring beans. These can delegate to your Scala service/core code.
A Scala-only solution is to use Eberhard Wolff's closure that creates a manual transaction. Usage:
transactional() {
// do stuff in transaction
}
https://github.com/ewolff/scala-spring/blob/master/src/main/scala/de/adesso/scalaspring/tx/TransactionManagement.scala
https://github.com/ewolff/scala-spring/blob/master/src/main/scala/de/adesso/scalaspring/tx/TransactionAttributeWithRollbackRules.scala
Found here: http://www.slideshare.net/ewolff/scala-and-spring (slide 41)
License: Apache
There is nothing special about Spring's #Transactional support in Scala and you can use it without any Java code. Just make sure that you have "pure" traits for beans, which implementations would use #Transactional annotation. You should also declare a bean with PlatformTransactionManager type (if you are using .xml-based Spring configuration, you should use "transactionManager" for bean name, see EnableTransactionManagement's JavaDoc for details). Also, if you are using annotation-based configuration classes, be sure that these classes are placed in their own dedicated files, i.e. don't place any other classes (companion object is OK) in the same file. Here is simple working example:
SomeService.scala:
trait SomeService {
def someMethod()
}
// it is safe to place impl in the same file, but still avoid doing it
class SomeServiceImpl extends SomeService {
#Transactional
def someMethod() {
// method body will be executed in transactional context
}
}
AppConfiguration.scala:
#Configuration
#EnableTransactionManagement
class AppConfiguration {
#Bean
def transactionManager(): PlatformTransactionManager = {
// bean with PlatformTransactionManager type is required
}
#Bean
def someService(): SomeService = {
// someService bean will be proxied with transaction support
new SomeServiceImpl
}
}
// companion object is OK here
object AppConfiguration {
// maybe some helper methods
}
// but DO NOT place any other trait/class/object in this file, otherwise Spring will behave incorrectly!

Resources