I'm studying Aspect Oriented Programming in Spring with #AspectJ
I write an example but when I run it I've an error
Here are the class that I write
package concert;
/**
*
* #author phate
*/
public interface Performance {
public void perform();
}
Class PerformanceImpl implements the Performance interface and implements perform method
package concert;
import org.springframework.stereotype.Service;
/**
*
* #author Dennis A. Boanini
*/
#Service
public class PerformanceImpl implements Performance{
#Override
public void perform() {
System.out.println("perform");
}
}
Class Audience is annotated with #Aspect and declare some Advice
package concert;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
/**
*
* #author Dennis A. Boanini
*/
#Component
#Aspect
public class Audience {
#Before("execution(* concert.Performance.perform(..))")
public void silenceCellPhones(){
System.out.println("Silencing cell phones");
}
#Before("execution(* concert.Performance.perform(..))")
public void takeSeats(){
System.out.println("Taking seats");
}
#AfterReturning("execution(* concert.Performance.perform(..))")
public void applause(){
System.out.println("CLAP CLAP CLAP");
}
#AfterThrowing("execution(* concert.Performance.perform(..))")
public void demandRefund(){
System.out.println("Demanding a refund");
}
}
Class ConcertConfig is the bean that autoproxy
package concert;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
/**
*
* #author Dennis A. Boanini
*/
#Configuration
#EnableAspectJAutoProxy
#ComponentScan
public class ConcertConfig{
#Bean
public Audience audience() {
return new Audience();
}
}
And this is the main class
public class Turing {
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(ConcertConfig.class);
ctx.refresh();
Performance userService = ctx.getBean(PerformanceImpl.class);
userService.perform();
}
}
If I run I receive this error
Exception in thread "main" org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [concert.PerformanceImpl] is defined
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:374)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:334)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1088)
at com.phate.spring.aop.example.Turing.main(Turing.java:32)
But if I eliminate the interface everything work correctly, why?
Related
If i keep #Pointcut("within(org.example.ShoppingCart.*)") in AuthenticationAspect.java then the authenticate method is NOT getting invoked BUT when i change to #Pointcut("within(org.example..*)") then it does get invoked.
Doesn't the 2nd PointCut below automatically include the first one?
#Pointcut("within(org.example.ShoppingCart.*)")
#Pointcut("within(org.example..*)")
i believe both of these should work.
Following is the code :
ShoppingCart.java
package org.example;
import org.springframework.stereotype.Component;
#Component
public class ShoppingCart {
public void checkout(String status)
{
System.out.println("Checkout method called");
}
}
AuthenticationAspect.java
package org.example;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
#Aspect
#Component
public class AuthenticationAspect {
#Pointcut("within(org.example.ShoppingCart.*)")
public void authenticationPointCut()
{
}
#Before("authenticationPointCut()")
public void authenticate()
{
System.out.println("Authentication is being performed");
}
}
Main.java
package org.example;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Main {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(BeanConfig.class);
ShoppingCart cart = context.getBean(ShoppingCart.class);
cart.checkout("CANCELLED");
}
}
BeanConfig.java
package org.example;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
#Configuration // Indicates this is a configuration class
#ComponentScan(basePackages = "org.example") // Indicates where to find the components/beans
#EnableAspectJAutoProxy // Enables the AspectJ features in project
public class BeanConfig {
}
i am learning spring aspect and unsure why the pointcut expression is not working .
Since the within pointcut designator limits matching to join points of certain types, the problem is your pointcut expression is matching types within ShoppingCart because of .* in the end. If you remove those characters it should work.
#Pointcut("within(org.example.ShoppingCart)")
public void authenticationPointCut(){}
I like to have an implementation of one #Scheduled job using different configuration properties of .ymlfile.
Means in my yaml file I describe the cron expression as a list:
job:
schedules:
- 10 * * * * *
- 20 * * * * *
I read those values out using Configuration and created a #Bean named scheduled:
#Configuration
#ConfigurationProperties(prefix="job", locations = "classpath:cronjob.yml")
public class CronConfig {
private List<String> schedules;
#Bean
public List<String> schedules() {
return this.schedules;
}
public List<String> getSchedules() {
return schedules;
}
public void setSchedules(List<String> schedules) {
this.schedules = schedules;
}
}
In my Job class I want to start the execution of one method but for both of the schedules in my configuration.
#Scheduled(cron = "#{#schedules}")
public String execute() {
System.out.println(converterService.test());
return "success";
}
With this solution the application creates an error: (more or less clear)
Encountered invalid #Scheduled method 'execute': Cron expression must consist of 6 fields (found 12 in "[10 * * * * *, 20 * * * * *]")
Is there a way to configure the same scheduled job method with multiple declarations of cron expressions?
EDIT 1
After some try I just used a second annotation on the executer method.
#Scheduled(cron = "#{#schedules[0]}")
#Scheduled(cron = "#{#schedules[1]}")
public String execute() {
System.out.println(converterService.test());
return "success";
}
This solution works but is not really dynamic. Is there also a way to make this dynamic?
(edit since I found a way to perform this)
You can actually do this. Below I'm showcasing a working example:
cronjob.yaml
job:
schedules:
- 10 * * * * *
- 20 * * * * *
the actual task to perform MyTask:
package hello;
import org.springframework.stereotype.Component;
#Component
public class MyTask implements Runnable {
#Override
public void run() {
//complicated stuff
}
}
Your CronConfig as is:
package hello;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.List;
#Configuration
#ConfigurationProperties(prefix="job", locations = "classpath:cronjob.yml")
public class CronConfig {
private List<String> schedules;
#Bean
public List<String> schedules() {
return this.schedules;
}
public List<String> getSchedules() {
return schedules;
}
public void setSchedules(List<String> schedules) {
this.schedules = schedules;
}
}
The ScheduledTask bean that is responsible to schedule all crons:
package hello;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Component;
#Component
public class ScheduledTasks {
#Autowired
private TaskScheduler taskScheduler;
#Autowired
private CronConfig cronConfig;
#Autowired
private MyTask myTask;
private static final Logger log = LoggerFactory.getLogger(ScheduledTasks.class);
public void scheduleAllCrons() {
cronConfig.getSchedules().forEach( cron -> taskScheduler.schedule(myTask, new CronTrigger(cron)) );
}
}
The context/main class Application:
package hello;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.concurrent.ConcurrentTaskScheduler;
#SpringBootApplication
#EnableScheduling
#EnableAsync
public class Application {
#Bean
public TaskScheduler taskScheduler() {
return new ConcurrentTaskScheduler();
}
public static void main(String[] args) throws Exception {
ApplicationContext ctx = SpringApplication.run(Application.class);
ScheduledTasks scheduledTasks = ctx.getBean(ScheduledTasks.class);
scheduledTasks.scheduleAllCrons();
}
}
application.yaml:
crontab:
submitSubtask: "0 * * * * *"
updateBacktrace: "2/30 * * * * *"
java code:
#EnableScheduling
public class Demo{
#Scheduled(cron = "${crontab.updateBacktrace}")
private void updateBacktrace() {
...
}
#Scheduled(cron = "${crontab.submitSubtask}")
private void submitSubtask() {
...
}
}
it works for springboot 2.3.7.
A trick related to it:
while defining the corn job timing, attribute name should be in lower case
for example: if it is in Camel case, spring did not kick the job :(
application.yml:
common:
scheduler:
feedeErrorLogCleanUp: 0 0/5 * ? * *
WHEREAS BELOW STUFF WORKS
common:
scheduler:
feedeerrorlogcleanUp: 0 0/5 * ? * *
I have a Data Loader Class which is suppose to load data once the app starts.
My Error -
Could not autowire. No beans of 'OwnerService' Found.
However, my ownerService class is annotated as I have shown below -
This is the class whose supposed to do that -
DataLoader
import model.Owner;
import model.Vet;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
import services.OwnerService;
import services.VetService;
import services.map.OwnerServiceMap;
import services.map.VetServiceMap;
#Component
public class DataLoader implements CommandLineRunner {
private final OwnerService ownerService;
private final VetService vetService;
public DataLoader(OwnerService ownerService, VetService vetService) {
this.ownerService = ownerService;
this.vetService = vetService;
}
OwnerServiceMap
package services.map;
import model.Owner;
import org.springframework.stereotype.Service;
import services.OwnerService;
import java.util.Set;
#Service
public class OwnerServiceMap extends AbstractMapService<Owner,Long> implements OwnerService
{//some code here}
The vetService is the same as ownerService.
My applcation class -
package petclinic;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class PetclinicApplication {
public static void main(String[] args) {
SpringApplication.run(PetclinicApplication.class, args);
}
}
Maybe I have hierarchy problems, as the application class doesn't search for beans in enough places in the project?
Thank you!
I'm trying to capture the execution of an advice using annotation in Maven, but it says that advice has not been applied. Here is the code:
package testMaven8;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
#Aspect
public class aspecter {
public static int a;
public void setA(int a) {
this.a = a;
}
public int getA() {
return a;
}
#Before("execution(* testMaven8.das.qwe(..))")
public void testBefore2(){
System.out.println("yoo2");
setA(102);
System.out.println(a);
}
#Before("execution (* testMaven8.aspecter.testBefore2(..))")
public void advice1(){
System.out.println("advicing advice testBefore2");
}
}
Is there something wrong with the code? I'm trying to avoid the usage of Aspect class if it's possible. Any help is appreciated.
Thanks
Advice execution is something special in AspectJ, not a normal method execution. Thus, if you want to capture advice execution you also need a special pointcut with the surprising name - adviceexecution() ;-)
Here is some sample code:
Driver application:
package de.scrum_master.app;
public class Application {
public static void main(String[] args) {
new Application().doSomething();
}
public void doSomething() {
System.out.println("Doing something");
}
}
Aspect capturing method executions:
package de.scrum_master.aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
#Aspect
public class MethodInterceptor {
#Before("execution(!static * *(..))")
public void interceptMethod(JoinPoint thisJoinPoint) {
System.out.println(thisJoinPoint);
}
}
Aspect capturing advice executions:
package de.scrum_master.aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
#Aspect
public class AdviceInterceptor {
#Before("!within(AdviceInterceptor) && adviceexecution()")
public void interceptAdvice(JoinPoint thisJoinPoint) {
System.out.println(thisJoinPoint);
}
}
Please do not try to pack the advice execution interceptor into the same aspect as another advice because you can easily end up in an endless recursion if you cannot exclude the adviceexecution() pointcut from capturing itself via !within(AdviceInterceptor).
Console log:
adviceexecution(void de.scrum_master.aspect.MethodInterceptor.interceptMethod(JoinPoint))
execution(void de.scrum_master.app.Application.doSomething())
Doing something
I'm getting an error whenever I'm using #Autowired annotation. The root error i get is
org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [jp.co.vmt.qt.C0002.C0002Dao] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
My interface is
/**
*
*/
package jp.co.vmt.qt.C0002;
import java.util.List;
import jp.co.vmt.qt.model.TmtProject;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
/**
* #author WINDOWS
*/
public interface C0002Dao extends JpaRepository<TmtProject, Long> {
#Query("SELECT PROJECT_ID, PROJECT_NAME FROM TmtProject")
public List<TmtProject> getAllProjects();
}
And my implementing class is
/**
*
*/
package jp.co.vmt.qt.C0002;
import java.util.List;
import jp.co.vmt.qt.model.TmtProject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Repository;
/**
* #author WINDOWS
*/
#Repository
public class C0002Service implements C0002Dao {
#Autowired
private C0002Dao c0002Dao;
/*
* (non-Javadoc)
* #see jp.co.vmt.qt.C0002.C0002Dao#getAllProjects()
*/
#Override
public List<TmtProject> getAllProjects() {
return this.c0002Dao.getAllProjects();
}
... other methods from extended interface
}
And here is where I used c0002Service
/**
*
*/
package jp.co.vmt.qt.C0002;
import java.util.List;
import jp.co.vmt.qt.model.TmtProject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.fasterxml.jackson.databind.ObjectMapper;
/**
* #author WINDOWS
*/
#Component
public class C0002Logic {
#Autowired
private C0002Dao c0002Service;
public String getProjectList() throws Exception {
List<TmtProject> projectList = this.c0002Service.getAllProjects();
ObjectMapper mapper = new ObjectMapper();
String jsonString = mapper.writeValueAsString(projectList);
return jsonString;
}
}
I have my C0002Logic autowired in my controller which is not shown here.
To my understanding, I created an interface (C0002Dao) and an implementing class (C0002Service) of that interface, which I marked with #Repository and I am autowiring the service to my Logic class (C0002Logic). However, I'm getting the error shown above. Any ideas on where I went wrong and how to solve them? Thanks
The problem is I believe
In C0002Service,
#Autowired
private C0002Dao c0002Dao;
U r trying to inject to C0002Dao at the time qualifying bean (instance of C0002Service) is about to be registered.