Spring Boot AOP Before Advice
1. Tổng quan
Ở bài viết trước chúng ta đã cùng tìm hiểu sơ qua về Spring AOP và các loại advice, bạn có thể xem lại bài viết ở đây.
Before advice được sử dụng trong lập trình hướng khía cạnh để đạt được kết quả xuyên suốt.
Nó là loại advice đảm bảo rằng một advice được chạy trước khi method thực hiện. Chúng ta có thể sử dụng annotation @Before để sử dụng before advice.
Ở bài viết này chúng ta hãy cùng tìm hiểu kỹ hơn loại advice này thông qua ví dụ dưới đây.
2. Ví dụ về Spring Boot before 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.Aspect; import org.aspectj.lang.annotation.Before; import org.springframework.stereotype.Component; @Aspect @Component public class EmployeeServiceAspect { @Before(value = "execution(* com.example.demo.service.EmployeeService.*(..))") public void beforeAdvice(JoinPoint joinPoint) { System.out.println("Before method:" + joinPoint.getSignature()); System.out.println("Creating Employee success"); } }
- 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 before advice. Trong bài viết tiếp theo chúng ta sẽ tìm hiểu về after advice và cách triển khai nó trong ứng dụng của mình.
Nguồn tham khảo: https://www.javatpoint.com/spring-boot-aop-before-advice
Để lại một bình luận