I am trying to understand how AspectJ works so I built this very simple example. I can execute x() from a web browser but applaud() never gets executed. Why? How can I get it executed (apart from calling it inside x())? I am trying to do all this without creating an xml.
My environment is Java, Spring, AspectJ, IntelliJ and Windows 10.
package hello;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
#RestController
#Aspect
#Configuration
#EnableAspectJAutoProxy
public class SomeClass {
#RequestMapping("/x")
#Pointcut("execution(* hello.SomeClass.x())")
public String x() {
System.out.println("in x");
return "<div><h1>Some content</h1></div>";
}
#After("hello.SomeClass.x()")
public void applaud() {
System.out.println("CLAPCLAPCLAPCLAPCLAP");
}
}
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 am trying to connect spring boot application with MySQL for that I have created a interface with name FilterDao which extend JpaRepository class. but whenever I try to make object of implemented class in Service I got this error "Consider defining a bean of type 'com.example.filter.FilterDao' in your configuration" as I am new to spring boot I don't understand this error.
FilterApplication.java
package com.example.filter;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
#SpringBootApplication(exclude = {DataSourceAutoConfiguration.class })
public class FilterApplication {
public static void main(String[] args) {
SpringApplication.run(FilterApplication.class, args);
}
}
FilterDao.java
package com.example.filter;
import com.example.filter.Filter;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.repository.query.FluentQuery;
import java.util.List;
import java.util.Optional;
import java.util.function.Function;
//#Configuration
public interface FilterDao extends JpaRepository<Filter, Integer> {
}
FilterService.java
package com.example.filter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
#Service
public class FilterService {
#Autowired
private FilterDao filterDao;
public List<Filter> getData() {
System.out.println("----------------------HERE-------------");
return filterDao.findAll();
}
}
FilterConnector.java
package com.example.filter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
#RestController
public class FilterConnector {
#Autowired
private FilterService filterService;
#GetMapping("/home")
public List<Filter> home()
{
return this.filterService.getData();
}
}
Project Structure
Annotate FilterDao with #Repository
Seems spring has not created bean for FilterDao repository and you are trying to use that`
#Autowired
private FilterDao filterDao;`
There might different reasons for this exception. Please try the below solution.
Use #EnableJpaRepositories(basePackages = "com.example.filter") with your FilterApplication class.
Use #ComponentScan(basePackages = "com.example.*") with FilterApplication class
Use #Repoitory annotation with FilterDao interface.
Hope this helps. For more details check the below tutorial.
https://javatute.com/jpa/consider-defining-a-bean-of-type-in-your-configuration/
Have SpringBoot Java app with different classes. I am not able to inject the dependencies and initialize/access the object of one class into another . Have seen the spring doc and used the annotations (#component,#Autowired etc. ), still there is an issue.
following are the classes.
Main Class ()
package com.test;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.stereotype.Component;
#SpringBootApplication
public class CostmanagementApplication {
public static void main(String[] args) {
SpringApplication.run(CostmanagementApplication.class, args);
}
}
Controller class
package com.test;
import javax.swing.text.rtf.RTFEditorKit;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
#Component
#Controller
public class HighChartsController {
#Autowired
private RequestToken rt;
#GetMapping("/costdata")
public static String customerForm(Model model) {
//here not able to access the getToken() method
model.addAttribute("costdata", new CostDataModel());
return "costdata";
}
}
RequestToken Class
package com.test;
import java.io.IOException;
import java.net.URI;
import java.net.URLEncoder;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpRequest.BodyPublishers;
import java.net.http.HttpResponse;
import java.net.http.HttpResponse.BodyHandlers;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.HashMap;
import java.util.stream.Collectors;
import org.json.JSONObject;
import org.springframework.stereotype.Component;
#Component
public class RequestToken {
public String getToken() throws IOException, InterruptedException {
// TODO Auto-generated method stub
// code to get the token
return token;
}
}
now eventhough , I have all annotation in place , not getting why the getToken() method is not accessible in controller class using rt object. please suggest
Okay, let's go in order.
First of all, all the annotations #Service, #Controller and #Repository are specifications from #Component, so you don't need to specify #Component and #Controller in your HighChartsController.
Actually, if you check what the annotation #Controller definition is, you'll find this:
#Component
public #interface Controller {
...
}
Secondly, I don't really know what do you mean with that you aren't able to access the getToken() method, but as you wrote it seems you tried to access to that method as an static method.
You're injecting the object, so you use the methods of the objects like in plain Java: rt.getToken(). The only difference is that the RequestToken object will be already initialized at the moment you call it.
package com.test;
import javax.swing.text.rtf.RTFEditorKit;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
#Controller
public class HighChartsController {
#Autowired
private RequestToken rt;
#GetMapping("/costdata")
public static String customerForm(Model model) {
String token = rt.getToken();
...
model.addAttribute("costdata", new CostDataModel());
return "costdata";
}
}
I have a rest controller contains many methods
#RestController
#RequestMapping("v1/test")
public class TestRestController {
...... 100 methods (GET, POST, PATCH, etc)
}
How can I know which method is being accessed without using print in each method?
Are there any ways to do that?
While you can use AOP tactics noted in the other answers to log the methods, there are better approaches if all you want to do is log all of the requests and responses for the endpoints those methods implement. There are a couple ways this can be done: Use Spring's CommonRequestLoggingFilter or write your own HandlerInterceptor. Here is a nice article on the first two options.
Using Aspect Oriented Programming with Spring:
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
#Aspect
public class SpringAspect {
private static final Logger LOG = LoggerFactory.getLogger(SpringAspect.class);
#Before("execution(* sample.package.path.TestRestController.*(..))")
public void executedMethodsLogger(JoinPoint joinPoint) {
LOG.info("[ Executed method {} ]", joinPoint.toString());
}
}
You can use Spring AOP:
package com.example;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
#Aspect
public class ExampleAspect {
#Before("execution(* com.example.TestRestController(..)")
public void log(JoinPoint joinPoint) {
System.out.println("Executing :" + joinPoint.toString());
}
}
package test.aop;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.velocity.VelocityAutoConfiguration;
import org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
#Component
#Aspect
class LoggingMonitor {
#AfterThrowing(
pointcut = "execution(* test.aop..foo(..))",
throwing = "error")
public void logAfterThrowing(JoinPoint joinPoint, Throwable error) {
System.out.println(joinPoint);
}
}
#Service
class MyBean {
void foo() {
throw new RuntimeException("run error");
}
}
#SpringBootApplication
public class App {
#Autowired
MyBean myBean;
#Bean
CommandLineRunner runner() {
return r -> {
System.out.println("Run");
myBean.foo();
};
}
public static void main(String[] args) {
SpringApplication.run(App.class);
}
}
I don't understand why the code above not working, but when I changed my pointcut to "* org.springframework.boot.CommandLineRunner.run(..)", it works.
Spring AOP works on public methods only. Make your method public, or revert to AspectJ.
Due to the proxy-based nature of Spring’s AOP framework, protected
methods are by definition not intercepted, neither for JDK proxies
(where this isn’t applicable) nor for CGLIB proxies (where this is
technically possible but not recommendable for AOP purposes). As a
consequence, any given pointcut will be matched against public methods
only! If your interception needs include protected/private methods or
even constructors, consider the use of Spring-driven native AspectJ
weaving instead of Spring’s proxy-based AOP framework. This
constitutes a different mode of AOP usage with different
characteristics, so be sure to make yourself familiar with weaving
first before making a decision.
Source