1. Gambaran keseluruhan
Dalam tutorial ini, kita akan melihat bagaimana perpustakaan Togglz dapat digunakan dengan aplikasi Spring Boot.
2. Togglz
The Togglz perpustakaan menyediakan pelaksanaan yang Ciri Bertukar-tukar corak reka bentuk. Pola ini merujuk kepada adanya mekanisme yang memungkinkan untuk menentukan semasa masa berjalan aplikasi sama ada fitur tertentu diaktifkan atau tidak berdasarkan toggle.
Menonaktifkan satu ciri pada waktu runtime mungkin berguna dalam pelbagai situasi seperti mengerjakan fitur baru yang belum lengkap, ingin membenarkan akses ke satu ciri hanya ke subset pengguna atau menjalankan pengujian A / B.
Pada bahagian berikut, kami akan membuat aspek yang memintas kaedah dengan anotasi yang memberikan nama ciri, dan menentukan apakah akan terus menjalankan kaedah bergantung pada apakah fitur itu diaktifkan atau tidak.
3. Pergantungan Maven
Bersama dengan pergantungan Spring Boot, perpustakaan Togglz menyediakan balang Spring Boot Starter:
org.springframework.boot spring-boot-starter-parent 2.0.1.RELEASE org.togglz togglz-spring-boot-starter 2.4.1 org.togglz togglz-spring-security 2.4.1 org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-data-jpa org.springframework.boot spring-boot-starter-test com.h2database h2 1.4.194
Versi terbaru dari togglz-spring-boot-starter, togglz-spring-security, spring-boot-starter-web, spring-boot-starter-data-jpa, spring-boot-starter-test, h2 boleh dimuat turun dari Maven Tengah.
4. Konfigurasi Togglz
The togglz-spring-boot-starter perpustakaan mengandungi auto-konfigurasi untuk mewujudkan kacang perlu seperti FeatureManager . Satu-satunya kacang yang perlu kami sediakan adalah kacangProvider .
Pertama, mari buat penghitungan yang menerapkan antara muka Feature dan mengandungi senarai nama ciri:
public enum MyFeatures implements Feature { @Label("Employee Management Feature") EMPLOYEE_MANAGEMENT_FEATURE; public boolean isActive() { return FeatureContext.getFeatureManager().isActive(this); } }
Penghitungan juga menentukan kaedah yang disebut isActive () yang mengesahkan sama ada ciri tertentu diaktifkan.
Kemudian kita dapat menentukan kacang jenis EnumBasedFeatureProvider dalam kelas konfigurasi Spring Boot:
@Configuration public class ToggleConfiguration { @Bean public FeatureProvider featureProvider() { return new EnumBasedFeatureProvider(MyFeatures.class); } }
5. Menciptakan Aspek
Seterusnya, kami akan membuat aspek yang memintas anotasi AssociatedFeature tersuai dan memeriksa ciri yang disediakan dalam parameter anotasi untuk menentukan sama ada ia aktif atau tidak:
@Aspect @Component public class FeaturesAspect { private static final Logger LOG = Logger.getLogger(FeaturesAspect.class); @Around( "@within(featureAssociation) || @annotation(featureAssociation)" ) public Object checkAspect(ProceedingJoinPoint joinPoint, FeatureAssociation featureAssociation) throws Throwable { if (featureAssociation.value().isActive()) { return joinPoint.proceed(); } else { LOG.info( "Feature " + featureAssociation.value().name() + " is not enabled!"); return null; } } }
Mari juga tentukan anotasi khusus yang disebut FeatureAssociation yang akan mempunyai parameter nilai () jenis MyFeatures enum:
@Retention(RetentionPolicy.RUNTIME) @Target({ ElementType.METHOD, ElementType.TYPE }) public @interface FeatureAssociation { MyFeatures value(); }
Sekiranya ciri tersebut aktif, aspek tersebut akan meneruskan pelaksanaan kaedah; jika tidak, ia akan log mesej tanpa menjalankan kod kaedah.
6. Pengaktifan Ciri
Ciri di Togglz boleh aktif atau tidak aktif. Tingkah laku ini dikendalikan oleh bendera yang diaktifkan dan pilihan strategi pengaktifan.
Untuk menetapkan bendera yang diaktifkan menjadi benar, kita dapat menggunakan anotasi @EnabledByDefault pada definisi nilai enum.
Perpustakaan Togglz juga menyediakan pelbagai strategi pengaktifan yang dapat digunakan untuk menentukan apakah fitur diaktifkan berdasarkan kondisi tertentu.
Dalam contoh kami, mari kita gunakan SystemPropertyActivationStrategy untuk EMPLOYEE_MANAGEMENT_FEATURE kami yang menilai keadaan ciri berdasarkan nilai harta Sistem. Nama dan nilai harta tanah yang diperlukan dapat ditentukan menggunakan anotasi @ActivationParameter :
public enum MyFeatures implements Feature { @Label("Employee Management Feature") @EnabledByDefault @DefaultActivationStrategy(id = SystemPropertyActivationStrategy.ID, parameters = { @ActivationParameter( name = SystemPropertyActivationStrategy.PARAM_PROPERTY_NAME, value = "employee.feature"), @ActivationParameter( name = SystemPropertyActivationStrategy.PARAM_PROPERTY_VALUE, value = "true") }) EMPLOYEE_MANAGEMENT_FEATURE; //... }
Kami telah menetapkan ciri kami untuk diaktifkan hanya jika harta pekerja . Ciri mempunyai nilai benar .
Jenis strategi pengaktifan lain yang disediakan oleh perpustakaan Togglz adalah:
- UsernameActivationStrategy - membolehkan ciri aktif untuk senarai pengguna yang ditentukan
- UserRoleActivationStrategy - peranan pengguna semasa digunakan untuk menentukan keadaan ciri
- ReleaseDateActivationStrategy - mengaktifkan ciri secara automatik pada tarikh dan waktu tertentu
- GradualActivationStrategy - membolehkan ciri untuk peratusan pengguna yang ditentukan
- ScriptEngineActivationStrategy - membenarkan penggunaan skrip tersuai yang ditulis dalam bahasa yang disokong oleh ScriptEngine JVM untuk menentukan sama ada ciri itu aktif atau tidak
- ServerIpActivationStrategy - ciri diaktifkan berdasarkan alamat IP pelayan
7. Menguji Aspek
7.1. Contoh Permohonan
Untuk melihat aspek kami dalam tindakan, mari buat contoh mudah yang mengandungi ciri untuk menguruskan pekerja organisasi.
Oleh kerana ciri ini akan dikembangkan, kita dapat menambahkan kaedah dan kelas yang diberi penjelasan dengan anotasi @AssociatedFeature kami dengan nilai EMPLOYEE_MANAGEMENT_FEATURE. Ini memastikan bahawa mereka hanya dapat diakses jika ciri tersebut aktif.
Pertama, mari tentukan kelas entiti Pekerja dan repositori berdasarkan Spring Data:
@Entity public class Employee { @Id private long id; private double salary; // standard constructor, getters, setters }
public interface EmployeeRepository extends CrudRepository{ }
Seterusnya, mari tambahkan EmployeeService dengan kaedah untuk meningkatkan gaji pekerja. Kami akan menambahkan anotasi @AssociatedFeature ke kaedah dengan parameter EMPLOYEE_MANAGEMENT_FEATURE :
@Service public class SalaryService { @Autowired EmployeeRepository employeeRepository; @FeatureAssociation(value = MyFeatures.EMPLOYEE_MANAGEMENT_FEATURE) public void increaseSalary(long id) { Employee employee = employeeRepository.findById(id).orElse(null); employee.setSalary(employee.getSalary() + employee.getSalary() * 0.1); employeeRepository.save(employee); } }
Kaedah ini akan dipanggil dari titik akhir kenaikan / kenaikan yang akan kami panggil untuk ujian:
@Controller public class SalaryController { @Autowired SalaryService salaryService; @PostMapping("/increaseSalary") @ResponseBody public void increaseSalary(@RequestParam long id) { salaryService.increaseSalary(id); } }
7.2. Ujian JUnit
Pertama, mari kita menambah ujian di mana kita panggil pemetaan POST kami selepas menetapkan employee.feature harta kepada palsu . Dalam kes ini, ciri tersebut tidak boleh aktif dan nilai gaji pekerja tidak boleh berubah:
@Test public void givenFeaturePropertyFalse_whenIncreaseSalary_thenNoIncrease() throws Exception { Employee emp = new Employee(1, 2000); employeeRepository.save(emp); System.setProperty("employee.feature", "false"); mockMvc.perform(post("/increaseSalary") .param("id", emp.getId() + "")) .andExpect(status().is(200)); emp = employeeRepository.findOne(1L); assertEquals("salary incorrect", 2000, emp.getSalary(), 0.5); }
Seterusnya, mari kita tambahkan ujian di mana kita melakukan panggilan setelah menetapkan sifat menjadi benar . Dalam kes ini, nilai gaji harus dinaikkan:
@Test public void givenFeaturePropertyTrue_whenIncreaseSalary_thenIncrease() throws Exception { Employee emp = new Employee(1, 2000); employeeRepository.save(emp); System.setProperty("employee.feature", "true"); mockMvc.perform(post("/increaseSalary") .param("id", emp.getId() + "")) .andExpect(status().is(200)); emp = employeeRepository.findById(1L).orElse(null); assertEquals("salary incorrect", 2200, emp.getSalary(), 0.5); }
8. Kesimpulan
Dalam tutorial ini, kami telah menunjukkan bagaimana kami dapat mengintegrasikan perpustakaan Togglz dengan Spring Boot dengan menggunakan aspek.
Kod sumber lengkap contoh boleh didapati di GitHub.