インターセプター AOP を通じてカスタム アノテーションを実装します。インターセプターは、指定されたアノテーションで実行されるメソッドとして機能します。AOP が担当します。インターセプター メソッドとアノテーションが有効になる場所 (動的アノテーションによるプロキシ クラス実装の生成) を織り込むため。
spring-boot-starter: Spring のいくつかのコア基本依存関係
spring-boot-starter-aop: 実装する Spring のいくつかの関連する依存関係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>
1.カスタム アノテーション クラス
@Target({ElementType.TYPE}) //说明了Annotation所修饰的对象范围,这里,的作用范围是类、接口(包括注解类型) 或enum @Retention(RetentionPolicy.RUNTIME) //自定义注解的有效期,Runtime:注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在 @Documented //标注生成javadoc的时候是否会被记录 public @interface EasyExceptionResult { }
2.インターセプタ クラス
/** * 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. ポイントカットアスペクトクラス
Interceptorの親クラスがAdviceであるため、MethodInterceptorの実装クラスをアスペクトの実行メソッドとして利用できます。
@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. カスタム アノテーションの使用
@Service @EasyExceptionResult //自定义异常捕获注解 public class EasyServiceImpl { public void testEasyResult(){ throw new NullPointerException("测试自定义注解"); } }
5. 効果
@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(); } }
@Target({ElementType.TYPE}) //说明了Annotation所修饰的对象范围,这里,的作用范围是类、接口(包括注解类型) 或enum @Retention(RetentionPolicy.RUNTIME) //自定义注解的有效期,Runtime:注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在 @Documented //标注生成javadoc的时候是否会被记录 public @interface EasyExceptionResult { }
@Target
このアノテーションを適用できる Java 要素のタイプを示しますDescription | |
---|---|
クラス、インターフェイス (注釈型を含む)、および列挙型に適用されます | |
プロパティ (列挙型の定数を含む) に適用されます | |
メソッドに適用されます | |
メソッドに適用される仮パラメータ | |
コンストラクターに適用される | |
ローカル変数に適用 | |
注釈タイプに適用 | |
パッケージに適用 | |
バージョン 1.8 の新機能、型変数に適用) | |
バージョン 1.8 の新機能で、型を使用するすべてのステートメント (宣言ステートメント、ジェネリックス、キャスト ステートメントの型など) |
注釈のライフサイクルを示します
Description | |
---|---|
コンパイル時に破棄され、クラス ファイルには含まれません | #RetentionPolicy.CLASS |
RetentionPolicy.RUNTIME | |
でマークされた要素を示します。アノテーションは Javadoc または同様のツールで文書化できます
@Inherited
@Inherited アノテーションの使用を示すアノテーション。マークされたクラスのサブクラスにも次の属性があります。このアノテーション
Cglib を通じて達成されますアノテーションを定義した後、実行時に必要な効果を実現するために、アノテーションとクラスをバインドする方法を検討する必要があります。ここで動的プロキシを導入できます。アノテーションのメカニズムは、次のように、メソッドが実行される前にクラスがコンパイルされるときにウィービング操作を実行することです。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(); } }
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); } }
1. ターゲット オブジェクトがインターフェイスを実装している場合、AOP を実装するためにデフォルトで JDK の動的プロキシが使用されます
2. ターゲット オブジェクトがインターフェイスを実装している場合、CGLIB の使用を強制できますAOP を実装するには
3. ターゲット オブジェクトがインターフェイスを実装していない場合は、CGLIB ライブラリを使用する必要があります。Spring は JDK ダイナミック プロキシと CGLIB の間で自動的に変換します。 AOP を実装するために CGLIB の使用を強制しますか?
(1) CGLIB ライブラリ SPRING_HOME/cglib/*.jar(2)JDK 動的プロキシと CGLIB バイトコード生成の違いは何ですか?
(1) JDK 動的プロキシは、インターフェイスを実装するクラスに対してのみプロキシを生成できますが、クラスに対しては生成できません (2) CGLIB は、主に指定されたクラスに対してプロキシを実装します。これは継承であるため、クラスまたはメソッドを Final として宣言しないことをお勧めします
以上がAOP とインターセプターを使用して SpringBoot にカスタム アノテーションを実装する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。