• AOP面向切面编程


    基于动态代理的,可以使用JDK,cglib两种代理方式

      aop就是动态代理的规范化,把动态代理的实现步骤定义,让开发人员用统一的方式使用动态代理。

    aop: Aspect Orient Programming
      Aspect:切面,给目标类增加的功能,就是切面
        特点:一般都是非业务方法,可以独立使用的;

      Orient:面向
      Programming:编程

    怎么理解面向切面编程?
      1.需要在分析项目功能时找出切面
      2.合理的安排切面的执行时间,在目标方法之前还是之后
      3.合理的安排切面执行的位置,在哪个类,哪个方法增加增强功能

    1.切面:
      表示增强的功能,完成某一个功能,非业务的,常见的有日志,事务、统计信息
    2.JoinPoint:连接点,链接业务方法和切面的位置,某类中的业务方法

    3.Pointcut:切入点,指多个连接点方法的集合,多个方法

    4.目标对象:给哪个类的方法增加功能,这个类就叫做目标类

    5.Advice:通知,表示切面功能执行的时间

    一个切面有3个关键要素
      1.切面的功能代码,作用
      2.切面的执行位置,使用Pointcut表示切面执行的位置
      3.切面的执行时机,使用Advice表示执行时间,在目标方法之前还是目标方法执行之后

    public class MyUtil {
    
    //切面功能
    public static void log(){
    System.out.println("增加日志功能");
    }
    
    public static void trans(){
    System.out.println("增加事务处理");
    }
    }
    

      

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    Object obj = null;
    String name = method.getName();
    if ("some".equals(name)){ //joinPoint 多个点是Pointcut
    MyUtil.log();
    obj = method.invoke(target,args);
    MyUtil.trans();
    }else {
    obj = method.invoke(target,args);
    }
    return obj;
    }
    

      


    aop的实现
      aop是一个规范,是动态的一个规范化,一个标准
      aop的技术实现框架:
      spring:主要在事务处理时使用aop,很少使用,比较笨重

    aspectJ:开源的,专门做aop的框架
      1.使用xml配置文件
      2.使用注解(一般使用注解)

    学习aspectJ框架的使用:aspectJ的5个通知注解
      1.切面的执行时间,在规范中叫做Advice(通知,增强)
        1)@Before
        2)@AfterReturning
        3)@Around
        4)@AfterThrowing
        5)@After

      2.表示切面执行的位置,使用的是切入点表达式。(*表示需要有的,?表示可选,各部分之间使用空格隔开)
        execution(访问权限? 方法的返回值* 方法声明*(参数) 异常类型?)

        * 0至多个任意字符
        .. 用在方法参数中,表示任意多个参数;用在包名后表示当前包及其子包路径
        + 用在类名后,表示当前类及其子类;用在接口后,表示当前接口及其实现类

        示例:execution(public * *(..))
        解释:指定切入点为任意公共方法
        execution(* set*(..))
        解释:任何一个以set开始的方法
        execution(* com.xyz.service.*.*(..))
        解释:指定包下的所有类的方法(不包含子包)
        execution(* com.xyz.service..*.*(..))
        解释:指定包下的所有类的方法(包含子包)

     aop的实现步骤总结

      1.创建maven项目,加入spring和aspectJ依赖

      2.创建接口和实现类

      3.创建切面类,类上添加@Aspects注解,添加增加功能的方法,方法上标注执行的时机和执行的位置,例如@Before(value="excution(* *..impl.*.*(..))")

      4.创建spring配置文件,声明目标对象和代理类对象,声明自动代理 <aop:aspectj-autoproxy/>

      5.创建测试类,获取目标类对象,执行方法

    实现步骤:
      1.新建maven项目
      2.加入依赖
        spring
        aspectJ
        junit
      3.创建目标类,接口和实现类
        目的:给类中的方法增加功能
      4.创建切面类
        在类的上面加注解@Aspect
        在类中定义方法,方法就是切面要执行的功能代码
        在方法的上面加入aspectJ中的通知注解,例如@Before
        需要指定切入点表达式execution()

      5.创建spring配置文件,声明对象,把对象交给容器统一管理
        使用注解或则使用配置文件的bean标签
        1.声明目标对象
        2.声明切面类对象
        3.声明AspectJ框架中的自动代理生成器标签
        自动代理生成器:用来完成代理对象的自动创建功能的

      6.创建测试类
        从spring容器中获取目标对象(实际就是代理对象),通过代理执行方法,实现aop的功能增强

    示例:

    public interface SomeService {
        void some(String name,Integer age);
    }
    

      

    public class SomeServiceImpl implements SomeService{
    
        @Override
        public void some(String name, Integer age) {
            System.out.println("some service 执行");
        }
    }
    

      

    @Aspect
    public class MyAspects {
        @Before(value = "execution(* *..impl.*.*(..))")
        public void exe(){
            System.out.println("执行时间:"+new Date());
        }
    
    }
    

      

     <bean class="com.demo.service.impl.SomeServiceImpl" id="service"/>
        <bean class="com.demo.service.aspect.MyAspects" id="aspects"/>
    
        <aop:aspectj-autoproxy/>
    

      

    public class MyTest {
        @Test
        public void test(){
            String config = "ApplicationContext.xml";
            ApplicationContext ac = new ClassPathXmlApplicationContext(config);
            SomeService service = (SomeService) ac.getBean("service");
            service.some("lise",20);
        }
    }
    

      

    参数joinPoint使用:

    @Aspect
    public class MyAspects {
        @Before(value = "execution(* *..impl.*.*(..))")
        public void exe(JoinPoint joinPoint){
            System.out.println("方法的签名(定义)="+joinPoint.getSignature());
            System.out.println("方法的名称"+joinPoint.getSignature().getName());
            //方法的实参
            Object[] args = joinPoint.getArgs();
            for (Object arg:args){
                System.out.println(arg);
            }
            System.out.println("执行时间:"+new Date());
        }
    
    }
    

      

    后置通知:

    public interface SomeService {
        void doSome(String name,Integer age);
    
        String doOther(String name,Integer age);
    }
    

      

    public class SomeServiceImpl implements SomeService {
        @Override
        public void doSome(String name, Integer age) {
            System.out.println("dosome 方法执行成功");
        }
    
        @Override
        public String doOther(String name, Integer age) {
            System.out.println("doother 方法执行成功");
            return "abc";
        }
    }
    

      

    @Aspect
    public class MyAspect {
    
        @Before(value = "execution(* *..ba01.*impl.*(..))")
        public void some(){
            System.out.println("执行时间:"+new Date());
        }
    
        /**
         * @AfterReturning 后置通知
         *  value表示切入点表达式
         *  returning自定义的变量,表示目标方法的返回值,自定义变量名必须和通知方法的形参名一样
         *
         *      特点:
         *      在目标方法执行之后执行
         *      能够获取到目标方法的返回值,可以根据这个返回值做不同的处理功能
         *      可以修改这个返回值
         *      相当于:Object res = doOther();
         * @param res
         */
    
        @AfterReturning(value = "execution(* *..*Impl.doOther(..))",returning = "res")
        public void myAfterReturning(Object res){
            //res是目标方法执行之后的返回值,根据返回值做切面的处理功能
            System.out.println("目标方法执行之后获取到的返回值是:"+res);
            if (res.equals("abc")){
                System.out.println("操作成功 ,提交事务");
            }else {
                System.out.println("发生异常 ,事务回滚");
            }
        }
    }
    

      

    <bean class="com.demo.ba01.SomeServiceImpl" id="service"/>
        <bean class="com.demo.ba01.MyAspect" id="aspect"/>
        <aop:aspectj-autoproxy/>
    

      

    public class MyTest {
        @Test
        public void test01(){
            String config = "ApplicationContext.xml";
            ApplicationContext ac = new ClassPathXmlApplicationContext(config);
            SomeService service = (SomeService) ac.getBean("service");
            //service.doSome("lisi",20);
            //System.out.println("====================");
            String other = service.doOther("mike", 21);
    
        }
    }
    

      

    思考:后置通知是在目标方法执行之后执行,如果目标方法返回值是一个引用类型,在后置通知方法中对引用类型的属性值就行修改,会不会影响最后的调用结果?

  • 相关阅读:
    sqlserver读取日志以及复制
    SqlServer 2012 清理日志 截断日志的方法
    android Qzone的App热补丁热修复技术
    热修复技术学习总结
    android免root hook框架legend
    Dalvik虚拟机java方法执行流程和Method结构体分析
    Andfix热修复技术使用
    OKHttp概览
    B-tree B+tree适合文件系统索引和MySQL索引
    B-tree B+tree B*Tree
  • 原文地址:https://www.cnblogs.com/ethnic/p/14581454.html
Copyright © 2020-2023  润新知