Spring Boot AOP After Returning Advice
1. Tổng quan
Bài viết này chúng ta sẽ tìm hiểu về After Returning Advice một loại advice của Spring AOP.
After Returning Advice được sử dụng với annotation @AfterReturning.
Chúng ta hãy cùng tìm hiểu loại advice này ở ví dụ dưới đây.
2. Ví dụ về Spring Boot After Returning Advice
- Bước 1: Đầu tiên chúng ta khởi tạo dự án SpringBoot trong IntelIJ như sau: File -> New -> New Project -> Spring Initiaizr
- Bước 2: Chọn Next và điền Group name, ở đây mình để com.example.
- Bước 3: Điền thông tin về Artifact, ở đây mình để là demo.
- Bước 4: Chọn type là Gradle và Java version 8 sau đó nhấn Next.
- Bước 5: Sau đó chọn các thư viện như sau để tạo ứng dụng. Ở đây mình sử dụng Lombok để tự động tạo ra các getter setter. Các bạn có thể xem bài viết chi tiết hơn tại đây:
- Bước 6: Đặt tên cho ứng dụng và nhấn finish để khởi tạo ứng dụng
- Bước 7: Mở file build.gralde và thêm thư viện AOP vào trong dependency.
implementation 'org.springframework.boot:spring-boot-starter-aop'
build.gradle
plugins { id 'org.springframework.boot' version '2.3.4.RELEASE' id 'io.spring.dependency-management' version '1.0.10.RELEASE' id 'java' } group = 'com.example' version = '0.0.1-SNAPSHOT' sourceCompatibility = '1.8' configurations { compileOnly { extendsFrom annotationProcessor } } repositories { mavenCentral() } dependencies { implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' implementation 'org.springframework.boot:spring-boot-starter-web' compileOnly 'org.projectlombok:lombok' runtimeOnly 'mysql:mysql-connector-java' annotationProcessor 'org.projectlombok:lombok' testImplementation('org.springframework.boot:spring-boot-starter-test') { exclude group: 'org.junit.vintage', module: 'junit-vintage-engine' } implementation 'org.springframework.boot:spring-boot-starter-aop' } test { useJUnitPlatform() }
- Bước 8: Mở file DemoApplication.java và thêm annotation @EnableAspectJAutoProxy vào trong class này.
@EnableAspectJAutoProxy(proxyTargetClass=true)
Nó cho phép hỗ trợ xử lý các thành phần được đánh dấu bằng annotation @Aspect của AspectJ. Nó được sử dụng với annotation @Configuration. Chúng ta có thể kiểm soát loại proxy bằng cách sử dụng thuộc tính proxyTargetClass. Giá trị mặc định của nó là false.
DemoApplication.java
package com.example.demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.EnableAspectJAutoProxy; @SpringBootApplication @EnableAspectJAutoProxy(proxyTargetClass=true) public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } }
- Bước 9: Tạo model Employee nằm trong package com.example.demo.model với các thuộc tính và phương thức sau:
- Các thuộc tính: employeeId, firstname, lastname.
- Tạo các phương thức Getter và Setter.
package com.example.demo.model; import lombok.Data; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; @Data @Entity public class Employee { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String employeeId; private String firstname; private String lastname; }
- Bước 10: Tạo controller EmployeeController nằm trong package com.example.demo.controller với các API thêm, sửa, xóa.
package com.example.demo.controller; import com.example.demo.model.Employee; import com.example.demo.service.IEmployeeService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import java.util.Optional; @RestController @CrossOrigin("*") @RequestMapping("/employees") public class EmployeeController { @Autowired private IEmployeeService employeeService; @GetMapping public ResponseEntity<Iterable<Employee>> getAllEmployee() { return new ResponseEntity<>(employeeService.findAll(), HttpStatus.OK); } @PostMapping public ResponseEntity<Employee> createNewEmployee(@RequestBody Employee employee) { return new ResponseEntity<>(employeeService.save(employee), HttpStatus.OK); } @GetMapping("/{id}") public ResponseEntity<Employee> getEmployee(@PathVariable Long id) { Optional<Employee> employeeOptional = employeeService.findById(id); return employeeOptional.map(employee -> new ResponseEntity<>(employee, HttpStatus.OK)) .orElseGet(() -> new ResponseEntity<>(HttpStatus.NOT_FOUND)); } @PutMapping("/{id}") public ResponseEntity<Employee> updateEmployee(@PathVariable Long id, @RequestBody Employee employee) { Optional<Employee> employeeOptional = employeeService.findById(id); return employeeOptional.map(employee1 -> { employee.setId(employee1.getId()); return new ResponseEntity<>(employeeService.save(employee), HttpStatus.OK); }).orElseGet(() -> new ResponseEntity<>(HttpStatus.NOT_FOUND)); } @DeleteMapping("/{id}") public ResponseEntity<Employee> deleteEmployee(@PathVariable Long id) { Optional<Employee> employeeOptional = employeeService.findById(id); return employeeOptional.map(employee -> { employeeService.remove(id); return new ResponseEntity<>(employee, HttpStatus.OK); }).orElseGet(() -> new ResponseEntity<>(HttpStatus.NOT_FOUND)); } }
- Bước 11: Tạo interface IGeneralService trong package com.example.demo.service và interface IEmployeeService kế thừa interface trên và một class EmployeeService implement interface IEmployeeService.
IGeneralService.java
package com.example.demo.service; import java.util.Optional; public interface IGeneralService<T> { Iterable<T> findAll(); Optional<T> findById(Long id); T save(T t); void remove(Long id); }
IEmployeeService.java
package com.example.demo.service; import com.example.demo.model.Employee; public interface IEmployeeService extends IGeneralService<Employee> { }
EmployeeService.java
package com.example.demo.service; import com.example.demo.model.Employee; import com.example.demo.repository.EmployeeRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.Optional; @Service public class EmployeeService implements IEmployeeService { @Autowired private EmployeeRepository employeeRepository; @Override public Iterable<Employee> findAll() { return employeeRepository.findAll(); } @Override public Optional<Employee> findById(Long id) { return employeeRepository.findById(id); } @Override public Employee save(Employee employee) { return employeeRepository.save(employee); } @Override public void remove(Long id) { employeeRepository.deleteById(id); } }
- Bước 12: Tạo interface EmployeeRepository kế thừa interface JpaRepository có sẵn của Spring Data Jpa trong package com.example.demo.repository.
package com.example.demo.repository; import com.example.demo.model.Employee; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; @Repository public interface EmployeeRepository extends JpaRepository<Employee, Long> { }
- Bước 13: Tạo một class có tên là EmployeeServiceAspect trong package com.example.demo.aspect.
package com.example.demo.aspect; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.Aspect; import org.springframework.stereotype.Component; @Aspect @Component public class EmployeeServiceAspect { @AfterReturning(value = "execution(* com.example.demo.service.EmployeeService.*(..))") public void afterReturningAdvice(JoinPoint joinPoint) throws Throwable { System.out.println("After Returing method: " + joinPoint.getSignature()); } }
- Bước 14: Cấu hình file application.propperties:
#Database spring.datasource.url=${JDBC_DATABASE_URL:} spring.datasource.username=root spring.datasource.password=123456 spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver #Hibernate spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect spring.jpa.properties.hibernate.id.new_generator_mappings = true spring.jpa.properties.hibernate.show.sql = true spring.jpa.properties.hibernate.format_sql = true spring.jpa.generate-ddl=true spring.jpa.properties.hibernate.hb2dll.auto = update logging.level.org.hibernate.SQL=DEBUG logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE
Ở đây mình sử dụng đến file *.env để cấu hình đường dẫn đến schema. Bạn có thể xem hướng dẫn cách sử dụng env trong Spring Boot tại đây.
local.env
JDBC_DATABASE_URL=jdbc:mysql://localhost:3306/demo_aop
- Bước 15: Khởi chạy ứng dụng và sử dụng postman để chạy đường dẫn sau và chọn phương thức POST: http://localhost:8080/employees.
Ở trên mình truyền dữ liệu dạng Json có các thông tin employeeId = 001, firstname = Quan, lastname = Nguyen.
- Bước 16: Mở màn hình console của ứng dụng và xem kết quả
3. Kết luận
Ở bài viết này chúng ta đã học được cách làm việc với After Returning Advice. Trong bài viết tiếp theo chúng ta sẽ tìm hiểu về loại advice cuối cùng trong AOP đó là After Throwing Advice và cách triển khai nó trong ứng dụng.
Nguồn: https://www.javatpoint.com/spring-boot-aop-after-returning-advice
Leave a Reply