implémentation d'annotations personnalisées via intercepteur + AOP, où l'intercepteur agit comme une méthode à exécuter au niveau de l'annotation spécifiée, et aop est responsable de la prise en compte de la méthode de l'intercepteur et de l'annotation. un tissage en place (générer une implémentation de classe proxy via une annotation dynamique).
spring-boot-starter : quelques dépendances de base de base de spring
spring-boot-starter-aop : quelques dépendances associées de spring implémentant Aop
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency>
@Target({ElementType.TYPE}) //说明了Annotation所修饰的对象范围,这里,的作用范围是类、接口(包括注解类型) 或enum @Retention(RetentionPolicy.RUNTIME) //自定义注解的有效期,Runtime:注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在 @Documented //标注生成javadoc的时候是否会被记录 public @interface EasyExceptionResult { }2. Classe Interceptor
/** * MethodInterceptor是AOP项目中的拦截器(注:不是动态代理拦截器), * 区别与HandlerInterceptor拦截目标时请求,它拦截的目标是方法。 */ public class EasyExceptionIntercepter implements MethodInterceptor { @Override public Object invoke(MethodInvocation invocation) throws Throwable { AnnotatedElement element=invocation.getThis().getClass(); EasyExceptionResult easyExceptionResult=element.getAnnotation(EasyExceptionResult.class); if (easyExceptionResult == null) { return invocation.proceed(); } try { return invocation.proceed(); } catch (Exception rpcException) { //不同环境下的一个异常处理 System.out.println("发生异常了"); return null; } } }3. Classe d'aspect Pointcut
La classe d'implémentation de MethodInterceptor peut être utilisée comme méthode d'exécution d'aspect car la classe parent d'Interceptor est Advice.
@Configuration public class EasyExceptionAdvisor { /** * 放在最后执行 * 等待ump/日志等记录结束 * * @return {@link DefaultPointcutAdvisor}对象 */ @Bean @Order(Integer.MIN_VALUE) public DefaultPointcutAdvisor easyExceptionResultAdvisor() { DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(); //针对EasyExceptionResult注解创建切点 AnnotationMatchingPointcut annotationMatchingPointcut = new AnnotationMatchingPointcut(EasyExceptionResult.class, true); EasyExceptionIntercepter interceptor = new EasyExceptionIntercepter(); advisor.setPointcut(annotationMatchingPointcut); //在切点执行interceptor中的invoke方法 advisor.setAdvice(interceptor); return advisor; } }
4. Utilisation d'annotations personnalisées
@Service @EasyExceptionResult //自定义异常捕获注解 public class EasyServiceImpl { public void testEasyResult(){ throw new NullPointerException("测试自定义注解"); } }5. Effet
@SpringBootApplication public class JdStudyApplication { public static void main(String[] args) { ConfigurableApplicationContext context=SpringApplication.run(JdStudyApplication.class, args); EasyServiceImpl easyService=context.getBean(EasyServiceImpl.class); easyService.testEasyResult(); } }
Jusqu'à présent, des annotations personnalisées ont été mises en œuvre jusqu'au printemps.
Java implémente des annotations personnaliséesBien que les annotations personnalisées soient implémentées via Spring, il existe encore des moyens pour nous d'implémenter des annotations personnalisées sans utiliser Spring. Après tout, les annotations sont antérieures à Spring. Il existe certaines méta-annotations dans le JDK, principalement @Target, @Retention, @Document et @Inherited, qui sont utilisées pour modifier les annotations.@Target({ElementType.TYPE}) //说明了Annotation所修饰的对象范围,这里,的作用范围是类、接口(包括注解类型) 或enum @Retention(RetentionPolicy.RUNTIME) //自定义注解的有效期,Runtime:注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在 @Documented //标注生成javadoc的时候是否会被记录 public @interface EasyExceptionResult { }
@Target
Indique le type d'élément Java auquel cette annotation peut être appliquée
ElementType.TYPE | |
---|---|
ElementType.FIELD | |
ElementType.METHOD | |
ElementType.PARAMETER | |
ElementType.CONSTRUCTOR | |
ElementType.LOCAL_VARIABLE | |
ElementType.ANNOTATION_TYPE | |
ElementType.PACK AGE | |
ElementType.TYPE_PARAMETER | |
ElementType.TYPE_USE | |
Indique le cycle de vie de l'annotation
RetentionPolicy.SOURCE | |
---|---|
RetentionPolicy.CLASS | |
RetentionPolicy.RUNTIME | |
indique que l'élément marqué par cette annotation peut être documenté par Javadoc ou des outils similaires
@Inherited
indique que l'annotation utilisant l'annotation @Inherited est une sous-classe de la classe marquée La classe aura également cette annotation
implémentée par CglibAprès avoir défini l'annotation, nous devons réfléchir à la manière de lier l'annotation et la classe ensemble pour obtenir l'effet souhaité pendant l'exécution. Ici. nous pouvons introduire le mécanisme de proxy dynamique, l'annotation veut effectuer l'opération avant que la méthode ne soit exécutée et une opération de tissage est effectuée lorsque la classe est compilée comme suit.public static void main(String[] args) { Class easyServiceImplClass=EasyServiceImpl.class; //判断该对象是否有我们自定义的@EasyExceptionResult注解 if(easyServiceImplClass.isAnnotationPresent(EasyExceptionResult.class)){ final EasyServiceImpl easyService=new EasyServiceImpl(); //cglib的字节码加强器 Enhancer enhancer=new Enhancer(); 将目标对象所在的类作为Enhaner类的父类 enhancer.setSuperclass(EasyServiceImpl.class); 通过实现MethodInterceptor实现方法回调,MethodInterceptor继承了Callback enhancer.setCallback(new MethodInterceptor() { @Override public Object intercept(Object proxy, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { try{ method.invoke(easyService, args); System.out.println("事务结束..."); }catch (Exception e){ System.out.println("发生异常了"); } return proxy; } }); Object obj= enhancer.create();; EasyServiceImpl easyServiceProxy=(EasyServiceImpl)obj; easyServiceProxy.testEasyResult(); } }
implémenté via le proxy dynamique JDk
public class EasyServiceImplProxy implements InvocationHandler { private EasyServiceImpl target; public void setTarget(EasyServiceImpl target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 这里可以做增强 System.out.println("已经是代理类啦"); try{ return method.invoke(proxy, args); }catch (Exception e){ System.out.println("发生异常了"); return null; } } /** * 生成代理类 * @return 代理类 */ public Object CreatProxyedObj() { return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this); } }La différence entre le proxy dynamique Cglib et JDKLe proxy dynamique Java utilise le mécanisme de réflexion pour générer une classe anonyme qui implémente l'interface proxy et l'appelle avant d'appeler la méthode spécifique InvokeHandler à gérer. Le proxy dynamique cglib utilise le package open source asm pour charger le fichier de classe de la classe d'objet proxy et le traiter en modifiant son bytecode pour générer une sous-classe. 1. Si l'objet cible implémente l'interface, le proxy dynamique du JDK sera utilisé par défaut pour implémenter AOP 2 Si l'objet cible implémente l'interface, vous pouvez forcer l'utilisation de CGLIB pour implémenter AOP.
3. Si l'objet cible n'implémente pas l'interface. , la bibliothèque CGLIB doit être utilisée, spring convertira automatiquement entre le proxy dynamique JDK et CGLIB
Comment forcer l'utilisation de CGLIB pour implémenter AOP ? (1) Ajoutez la bibliothèque CGLIB, SPRING_HOME/cglib/*.jar (2) Ajoutez
(1) Le proxy dynamique JDK ne peut générer des proxys que pour les classes qui implémentent des interfaces, mais pas pour les classes (2) CGLIB implémente des proxys pour les classes, principalement pour générer une sous-classe pour la classe spécifiée et la couvrir Méthode
Parce que c'est hérité, il est préférable de ne pas déclarer la classe ou la méthode comme finale
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!