- Lựa chọn điểm cắt
// Định nghĩa điểm cắt
@Pointcut("execution(public * com.example.Repository+.*(..))")
public void repositoryMethods() {
}
// Sử dụng điểm cắt
@Around("repositoryMethods")
public Object execute(ProceedingJoinPoint joinPoint) throws Throwable {
return joinPoint.proceed();
}
AspectJ không phổ biến nhưng rất hiệu quả. Spring sẽ tạo một đối tượng aspect khi được định nghĩa.
Nếu chúng ta thêm các gói cần thiết, liệu có thể tạo ra các chú thích tương ứng cho các đối tượng của mình? Điều này phụ thuộc vào lựa chọn điểm cắt, do đó giới hạn phạm vi gói để tránh lạm dụng.
Một số kiểu định nghĩa điểm cắt: AspectJ - cú pháp điểm cắt (1) bắt các kết nối phương thức.
- Sử dụng chú thích
Chú thích là tính năng tự động của JDK và có thể lấy thông tin qua phản xạ.
package com.demo.annotation;
import java.lang.annotation.*;
@Documented
@Target({ElementType.TYPE, ElementType.METHOD})
@Inherited
@Retention(RetentionPolicy.SOURCE)
public @interface CustomAnnotation {
String description() default "default";
String note() default "note";
}
AspectJ cũng có thể sử dụng chú thích để xác định điểm cắt. Đồng thời, chúng ta có thể quét toàn bộ gói.
- Sử dụng Spring BeanUtils
BeanUtil chủ yếu dùng để sao chép thuộc tính đối tượng, nhưng nó cũng sao chép giá trị null từ đối tượng nguồn. Khi không mong muốn điều này, cần loại bỏ các thuộc tính null.
// Bỏ qua giá trị null
public static String[] getNullPropertyNames(Object source) {
BeanWrapper wrapper = new BeanWrapperImpl(source);
PropertyDescriptor[] props = wrapper.getPropertyDescriptors();
Set<String> nullNames = new HashSet<>();
for (PropertyDescriptor prop : props) {
Object value = wrapper.getPropertyValue(prop.getName());
if (value == null)
nullNames.add(prop.getName());
}
return nullNames.toArray(new String[0]);
}
BeanWrapper rất hữu ích khi truy cập các thuộc tính get/set.
- Sử dụng Class.forName
public DataSource createDataSource() throws Exception {
Class<?> clazz = Class.forName("com.ctrip.datasource.DalFactory");
Object instance = clazz.getDeclaredConstructor().newInstance();
Method method = clazz.getMethod("createConnection", String.class, String.class);
DataSource dataSource = (DataSource) method.invoke(instance, this.config.getDbName(), this.config.getUrl());
return dataSource;
}
Class.forName được sử dụng thay vì ClassLoader vì nó thực thi khối tĩnh trong quá trình tải Driver, đăng ký với DriverManager.
Sự khác biệt giữa Class.forName và ClassLoader trong Java Reflection.
- Đọc biến môi trường
Sử dụng giao diện cung cấp bởi Spring:
MapPropertySource source = new MapPropertySource("custom", new HashMap<>());
this.environment.getPropertySources().addLast(source);
Chủ yếu là sử dụng ConfigureableEnvironment.
- Cơ chế SPI trong ngôn ngữ Java
Cơ chế SPI (Service Provider Interface) là cách phát hiện dịch vụ bằng cách cấu hình tên đầy đủ của lớp triển khai vào tệp cấu hình, sau đó tải lớp triển khai tại thời gian chạy.
Spring SPI chỉ định tệp cấu hình nằm trong META-INF/spring.factories, tất cả các điểm mở rộng được đặt trong một tệp. Tệp cấu hình dạng key-value, key là tên đầy đủ của interface, value là tên đầy đủ của lớp triển khai.
Với cơ chế này, việc sử dụng Redis trong Spring Boot trở nên mượt mà như JDBC.