博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
SpringAOP03 项目脚手架、自定义注解、织入切面、引介增强
阅读量:4547 次
发布时间:2019-06-08

本文共 20052 字,大约阅读时间需要 66 分钟。

 

1 项目脚手架

  利用 Maven 进行创建

  1.1 利用IDEA创建一个Maven原型项目

    技巧01:原型Maven项目是没有webapp文件夹和resources项目文件夹的,需要自己手动创建;创建完后需要进行模块配置 file -> project structure -> modules

    

    

 

  1.2 配置 pom.xml 文件

    需要引入一些 spring 和 aop 相关的依赖

4.0.0
cn.xiangxu.com
aop_base_demo
1.0-SNAPSHOT
aop_base_demo
http://www.example.com
UTF-8
1.7
1.7
UTF-8
4.2.2.RELEASE
6.8.7
4.0
3.0
1.8.1
1.0
1.9
1.7.5
org.springframework
spring-beans
${spring.version}
org.springframework
spring-context
${spring.version}
org.springframework
spring-context-support
${spring.version}
org.ow2.asm
asm
${asm.version}
org.ow2.asm
asm-util
${asm.version}
cglib
cglib
${cglib.version}
asm
org.ow2.asm
org.aspectj
aspectjrt
${aspectj.version}
org.aspectj
aspectjweaver
${aspectj.version}
aopalliance
aopalliance
${aopalliance.version}
commons-codec
commons-codec
${commons-codec.version}
org.testng
testng
${testng.version}
test
org.springframework
spring-test
${spring.version}
test
org.apache.maven.plugins
maven-surefire-plugin
2.7.2
once
10
-Dfile.encoding=UTF-8
pom.xml

  1.3 刷新maven下载相关依赖

    技巧01:最好不要使用自带的maven仓库,使用自己修改过仓库地址的maven

    

    

 

2 自定义注解

  2.1 利用 @interface 创建

    技巧01:@Retention 用来指定注解有效范围,@Target 用来指定注解的使用范围

package cn.xiangxu.com.annotations;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.METHOD)public @interface NeedTest {    boolean value() default true;}
/* * Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved. * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. * * * */package java.lang.annotation;/** * Annotation retention policy.  The constants of this enumerated type * describe the various policies for retaining annotations.  They are used * in conjunction with the {@link Retention} meta-annotation type to specify * how long annotations are to be retained. * * @author  Joshua Bloch * @since 1.5 */public enum RetentionPolicy {    /**     * Annotations are to be discarded by the compiler.     */    SOURCE,    /**     * Annotations are to be recorded in the class file by the compiler     * but need not be retained by the VM at run time.  This is the default     * behavior.     */    CLASS,    /**     * Annotations are to be recorded in the class file by the compiler and     * retained by the VM at run time, so they may be read reflectively.     *     * @see java.lang.reflect.AnnotatedElement     */    RUNTIME}
RetentionPolicy.java
/* * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. * * * * * * * * * * * * * * * * * * * * */package java.lang.annotation;/** * The constants of this enumerated type provide a simple classification of the * syntactic locations where annotations may appear in a Java program. These * constants are used in {
@link Target java.lang.annotation.Target} * meta-annotations to specify where it is legal to write annotations of a * given type. * *

The syntactic locations where annotations may appear are split into * declaration contexts , where annotations apply to declarations, and * type contexts , where annotations apply to types used in * declarations and expressions. * *

The constants {

@link #ANNOTATION_TYPE} , {
@link #CONSTRUCTOR} , {
@link * #FIELD} , {
@link #LOCAL_VARIABLE} , {
@link #METHOD} , {
@link #PACKAGE} , * {
@link #PARAMETER} , {
@link #TYPE} , and {
@link #TYPE_PARAMETER} correspond * to the declaration contexts in JLS 9.6.4.1. * *

For example, an annotation whose type is meta-annotated with * {

@code @Target(ElementType.FIELD)} may only be written as a modifier for a * field declaration. * *

The constant {

@link #TYPE_USE} corresponds to the 15 type contexts in JLS * 4.11, as well as to two declaration contexts: type declarations (including * annotation type declarations) and type parameter declarations. * *

For example, an annotation whose type is meta-annotated with * {

@code @Target(ElementType.TYPE_USE)} may be written on the type of a field * (or within the type of the field, if it is a nested, parameterized, or array * type), and may also appear as a modifier for, say, a class declaration. * *

The {

@code TYPE_USE} constant includes type declarations and type * parameter declarations as a convenience for designers of type checkers which * give semantics to annotation types. For example, if the annotation type * {
@code NonNull} is meta-annotated with * {
@code @Target(ElementType.TYPE_USE)}, then {
@code @NonNull} * {
@code class C {...}} could be treated by a type checker as indicating that * all variables of class {
@code C} are non-null, while still allowing * variables of other classes to be non-null or not non-null based on whether * {
@code @NonNull} appears at the variable's declaration. * * @author Joshua Bloch * @since 1.5 * @jls 9.6.4.1 @Target * @jls 4.1 The Kinds of Types and Values */public enum ElementType { /** Class, interface (including annotation type), or enum declaration */ TYPE, /** Field declaration (includes enum constants) */ FIELD, /** Method declaration */ METHOD, /** Formal parameter declaration */ PARAMETER, /** Constructor declaration */ CONSTRUCTOR, /** Local variable declaration */ LOCAL_VARIABLE, /** Annotation type declaration */ ANNOTATION_TYPE, /** Package declaration */ PACKAGE, /** * Type parameter declaration * * @since 1.8 */ TYPE_PARAMETER, /** * Use of a type * * @since 1.8 */ TYPE_USE}

ElementType.java

  2.2 使用注解

    2.2.1 随便创建一个服务类

      技巧01:在该服务类中的方法中使用自定义的注解即可

package cn.xiangxu.com.service;import cn.xiangxu.com.annotations.NeedTest;import org.springframework.stereotype.Service;/** * @author 王杨帅 * @create 2018-05-04 10:28 * @desc 自定义注解测试类 **/@Servicepublic class AnnotationTestService {    @NeedTest    public void deleteUser(Integer userId) {        System.out.println("根据用户ID删除用户所有信息:" + userId);    }    @NeedTest(value = false)    public void deleteUserAddress(String address) {        System.out.println("删除用户地址信息:" + address);    }}

    2.2.2 创建一个测试类

      该测试类主要功能是获取注解对象信息

      技巧01:getClass() 获取运行时的class信息,getDeclaredMethods() 获取已经声明的方法,getAnnotation 用来获取注解对象信息

package cn.xiangxu.com.service;import cn.xiangxu.com.annotations.NeedTest;import org.springframework.beans.factory.annotation.Autowired;import org.testng.annotations.Guice;import org.testng.annotations.Test;import javax.annotation.Resource;import java.lang.reflect.Method;import static org.testng.Assert.*;public class AnnotationTestServiceTest {    @Test    public void tool() {        // 01 获取到AnnotationTestService对象        AnnotationTestService annotationTestService = new AnnotationTestService();        // 02 获取到AnnotationTestService中所有的Method数组        Method [] methods = annotationTestService.getClass().getDeclaredMethods();        System.out.println(methods.length);        // 03 获取到方法上的注解信息        for (Method method : methods) {            NeedTest needTest = method.getAnnotation(NeedTest.class);            if (needTest != null) {                if (needTest.value()) {                    System.out.println(method.getName() + "()需要进行单元测试");                } else{                    System.out.println(method.getName() + "()不需要进行单元测试");                }            }        }    }    @Test    public void testDeleteUser() throws Exception {    }    @Test    public void testDeleteUserAddress() throws Exception {    }}
AnnotationTestServiceTest.java
/**     * Returns the runtime class of this {
@code Object}. The returned * {
@code Class} object is the object that is locked by {
@code * static synchronized} methods of the represented class. * *

The actual result type is {

@code Class
} * where {
@code |X|} is the erasure of the static type of the * expression on which {
@code getClass} is called.
For * example, no cast is required in this code fragment:

* *

* {

@code Number n = 0; }
* {
@code Class
c = n.getClass(); } *

* * @return The {
@code Class} object that represents the runtime * class of this object. * @jls 15.8.2 Class Literals */ public final native Class
getClass();
getClass()
/**     *     * Returns an array containing {
@code Method} objects reflecting all the * declared methods of the class or interface represented by this {
@code * Class} object, including public, protected, default (package) * access, and private methods, but excluding inherited methods. * *

If this {

@code Class} object represents a type that has multiple * declared methods with the same name and parameter types, but different * return types, then the returned array has a {
@code Method} object for * each such method. * *

If this {

@code Class} object represents a type that has a class * initialization method {
@code
}, then the returned array does *
not have a corresponding {
@code Method} object. * *

If this {

@code Class} object represents a class or interface with no * declared methods, then the returned array has length 0. * *

If this {

@code Class} object represents an array type, a primitive * type, or void, then the returned array has length 0. * *

The elements in the returned array are not sorted and are not in any * particular order. * * @return the array of {

@code Method} objects representing all the * declared methods of this class * @throws SecurityException * If a security manager, s, is present and any of the * following conditions is met: * *

    * *
  • the caller's class loader is not the same as the * class loader of this class and invocation of * {
    @link SecurityManager#checkPermission * s.checkPermission} method with * {
    @code RuntimePermission("accessDeclaredMembers")} * denies access to the declared methods within this class * *
  • the caller's class loader is not the same as or an * ancestor of the class loader for the current class and * invocation of {
    @link SecurityManager#checkPackageAccess * s.checkPackageAccess()} denies access to the package * of this class * *
* * @jls 8.2 Class Members * @jls 8.4 Method Declarations * @since JDK1.1 */ @CallerSensitive public Method[] getDeclaredMethods() throws SecurityException { checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true); return copyMethods(privateGetDeclaredMethods(false)); }
getDeclaredMethods()
/**     * {
@inheritDoc} * @throws NullPointerException {
@inheritDoc} * @since 1.5 */ public
T getAnnotation(Class
annotationClass) { return super.getAnnotation(annotationClass); }
getAnnotation()

 

3 切面样例

  3.1 创建所需的服务接口和服务类

    说明:Waiter 是一个接口利用有两个方法,其中greetTo方法有@NeedTest注解;NaiveWaiter是Waiter接口的实现类

package cn.xiangxu.com.service;import cn.xiangxu.com.annotations.NeedTest;public interface Waiter {    @NeedTest    public void greetTo(String clientName);        public void serveTo(String clientName);}
Waiter.java
package cn.xiangxu.com.service;public class NaiveWaiter implements Waiter {    public void greetTo(String clientName) {        System.out.println("NaiveWaiter:greet to "+clientName+"...");    }        public void serveTo(String clientName){        System.out.println("NaiveWaiter:serving "+clientName+"...");    }    public void smile(String clientName,int times){        System.out.println("NaiveWaiter:smile to  "+clientName+ times+"times...");    }    }
NaiveWaiter.java

  3.2 创建切面类

    技巧01:一个完整的切面类必须包含: 切点、增强、横切逻辑

package cn.xiangxu.com.aops.example;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Before;/** * @author 王杨帅 * @create 2018-05-04 11:09 * @desc **/@Aspectpublic class PreGreetingAspect {    @Before("execution(* greetTo(..))")    public void beforeGreeting() {        System.out.println("How are you");    }}
PreGreetingAspect.java

  3.3 织入切面

    3.3.1 通过编程方式

      利用 AspectJProxyFactory 织如基于 @AspectJ注解的类

package cn.xiangxu.com.aops.example;import cn.xiangxu.com.service.NaiveWaiter;import cn.xiangxu.com.service.Waiter;import org.springframework.aop.aspectj.annotation.AspectJProxyFactory;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;import org.testng.annotations.Test;import javax.annotation.Resource;import static org.testng.Assert.*;public class PreGreetingAspectTest {    @Test    public void testBeforeGreeting() throws Exception {        // 01 生成目标对象实例        Waiter target = new NaiveWaiter();        // 02 实例化工厂        AspectJProxyFactory factory = new AspectJProxyFactory();        // 03 设置目标对象        factory.setTarget(target);        // 04 添加切面类        factory.addAspect(PreGreetingAspect.class);        // 05 生成植入切面的代理对象        Waiter proxy = factory.getProxy();        // 06 利用代理对象调用方法        proxy.greetTo("Warrior");        System.out.println("parting line");        proxy.serveTo("Warrior");    }}
PreGreetingAspectTest.java

    3.3.2 利用Spring配置的方式

      》spring 配置文件

View Code

      》测试类

package cn.xiangxu.com.aops.example;import cn.xiangxu.com.service.NaiveWaiter;import cn.xiangxu.com.service.Waiter;import javafx.application.Application;import org.springframework.aop.aspectj.annotation.AspectJProxyFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;import org.testng.annotations.Test;import javax.annotation.Resource;import static org.testng.Assert.*;public class PreGreetingAspectTest {    /**     * 利用 编码的方式织入切面     * @throws Exception     */    @Test    public void testBeforeGreeting() throws Exception {        // 01 生成目标对象实例        Waiter target = new NaiveWaiter();        // 02 实例化工厂        AspectJProxyFactory factory = new AspectJProxyFactory();        // 03 设置目标对象        factory.setTarget(target);        // 04 添加切面类        factory.addAspect(PreGreetingAspect.class);        // 05 生成植入切面的代理对象        Waiter proxy = factory.getProxy();        // 06 利用代理对象调用方法        proxy.greetTo("Warrior");        System.out.println("parting line");        proxy.serveTo("Warrior");    }    /**     * 利用Spring配置的方式织入切面     */    @Test    public void testBeforeGreeting02() {        // 01 配置文件路径        String configPath = "aops/example/beans.xml";        // 02 获取应用上下文        ApplicationContext ac = new ClassPathXmlApplicationContext(configPath);        // 03 利用应用上下文获取对象        Waiter waiter = (Waiter)ac.getBean("waiter");        waiter.greetTo("fury");        System.out.println("===parting line===");        waiter.serveTo("warrior");    }}
PreGreetingAspectTest.java

 

4 引介增强

  引介增强最主要的目的是为类A添加一个需要实现的接口B,并指定实现类C(解释:C是B的实现类);简而言之,类A可以通过引介增强来实现接口B,实现的方式是利用了类C

  4.1 创建接口B

package cn.xiangxu.com.service;public interface Seller {  int sell(String goods, String clientName);}
Seller.java

  4.2 创建接口B的实现类C

package cn.xiangxu.com.service;public class SmartSeller implements Seller {    public int sell(String goods,String clientName) {        System.out.println("SmartSeller: sell "+goods +" to "+clientName+"...");        return 100;    }        public void checkBill(int billId){        if(billId == 1) throw new IllegalArgumentException("iae Exception");        else throw new RuntimeException("re Exception");    }}
SmartSeller.java

  4.3 创建切面类

    该切面类主要实现引介增强

package cn.xiangxu.com.aops.basic;import cn.xiangxu.com.service.Seller;import cn.xiangxu.com.service.SmartSeller;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.DeclareParents;@Aspectpublic class EnableSellerAspect {    @DeclareParents(value="cn.xiangxu.com.service.NaiveWaiter",            defaultImpl=SmartSeller.class)    public  Seller seller;}
EnableSellerAspect.java

  4.4 spring配置文件

View Code

  4.5 编写测试类

package cn.xiangxu.com.aops.basic;import cn.xiangxu.com.service.Seller;import cn.xiangxu.com.service.Waiter;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;import org.testng.annotations.Test;public class EnableSellerAspectTest {    @Test    public void test01() {        // 01 配置文件路径        String configPath = "aops/basic/beans.xml";        // 02 实例化应用上下文        ApplicationContext ac = new ClassPathXmlApplicationContext(configPath);        // 03 获取bean对象        Waiter waiter = (Waiter)ac.getBean("waiter");        // 04 调用实例方法        waiter.greetTo("fury");        // 05 类型强转        Seller seller = (Seller)waiter;        seller.sell("hotpot", "王杨帅");    }}
EnableSellerAspectTest.java

   

5 本博文源代码

  

    

  

 

 

 

 

 

 

 

    

 

转载于:https://www.cnblogs.com/NeverCtrl-C/p/8990665.html

你可能感兴趣的文章
拓扑图软件技术对比(转载)
查看>>
学习笔记——CDQ分治
查看>>
java校验银行卡号
查看>>
使用Jquery Viewer 展示图片信息
查看>>
mysql 备份
查看>>
USACO 3.2 Factorials
查看>>
maven学习
查看>>
项目人力资源管理
查看>>
Winform ListView虚拟模式
查看>>
j2ee 分布式布署 RPC基础知识
查看>>
Ext.Net学习笔记23:Ext.Net TabPanel用法详解
查看>>
机器学习---算法---支持向量机---线性SVM--第一部分
查看>>
高并发服务器---基础----IO模式和IO多路复用
查看>>
web-Amazon
查看>>
[springmvc]mapping request
查看>>
计算机网络——拥塞控制
查看>>
Gradle命令行黑魔法
查看>>
结对开发Ⅱ—利用文本求二维数组最大的子数组的和
查看>>
ios input样式
查看>>
Python2.7-argparse
查看>>