post-image

Spring Boot AOP After Throwing Advice

AOP

1. Tổng quan

Bài viết này chúng ta sẽ tìm hiểu về loại advice cuối cùng của Spring AOP đó là After Throwing Advice.

Nó được gọi khi một phương thức của chúng ta ném ra một ngoại lệ. After Throwing Advice được sử dụng với annotation @AfterThrowing.

Cú pháp:

@AfterThrowing(PointCut="execution(expression) ", throwing="name")  

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 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) throws Exception{
        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.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class EmployeeServiceAspect {
    @AfterThrowing(value = "execution(* com.example.demo.service.EmployeeService.*(..))")
    public void afterReturningAdvice(JoinPoint joinPoint) throws Throwable {
        System.out.println("After Throwing 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

Vậy là chúng ta đã tìm hiểu loại Advice cuối cùng của AOP ở bài viết này. Các bạn có thể tìm và đọc lại các bài liên quan tới AOP ở đây.

Nguồn: https://www.javatpoint.com/spring-boot-aop-after-throwing-advice

Leave a Reply

Your email address will not be published. Required fields are marked *