当前位置: 首页 > news >正文

《深入理解AOP编程:从基础概念到Spring实现》

AOP编程

AOP(Aspect Oriented Programing) 面向切面编程 =Spring动态代理开发

以切面为基本单位的程序开发,通过切脉你间的彼此协同,相互调用,完成程序构建

切面=切入点+额外功能


OOP(Object Oriented Programing)面向对象编程 java
以对象为基本单位的程序开发,通过对象间的彼此协同,相互调用,完成程序构建


POP(Procedure Oriented Programing)面向过程(方法、函数)编程

以过程为基本单位程序开发,通过过程间的彼此协同,相互调用,完成程序构建

AOP概念

        本质是Spring的动态代理开发,通过代理类为原始类增加额外功能

        好处:利于原始类的维护

注意:AOP编程不可能取代OOP OOP编程的补充

 AOP编程开发步骤

1.原始对象

2.额外功能

3.切入点

4.组装切面(额外功能+切入点)

名词解释

切面=切入点+额外功能
 

几何学

        面=点+相同性质

             方法+相同的功能

 AOP底层实现原理

1.核心问题

1.AOP如何创建动态代理类(动态字节码技术)

2.Spring工厂如何加工创建代理对象

        通过原始对象的id值,获得是代理对象

 2.动态代理类的创建

 2.1JDK动态代理

类加载器作用:ClassLoader

1.通过类加载器把对应类的字节码文件加载倒JVM

2.通过类加载器创建类的Class对象,进而创建这个类的对象

User--->user

User类Class对象 --->new User() -->user

如何获得类加载器:每一个类的.class文件 自动分配与之对应的ClassLoader


public class TestJDKProxy {
    /*
        借类加载器 可以借用其它类
     */
    public static void main(String[] args) {
        //创建原始对象
        UserService userService=new UserServiceImpl();
        //JDK创建动态代理

        InvocationHandler handler=new InvocationHandler() {

            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("代理功能");
                Object ret=method.invoke(userService,args);
                return ret;
            }
        };
        UserService userServiceProxy=(UserService) Proxy.newProxyInstance(TestJDKProxy.class.getClassLoader(),userService.getClass().getInterfaces(),handler);
        userServiceProxy.register(new proxy.User("zhangsan","123456"));
    }
}

2.2 CGlib动态代理

 CGlib创建动态代理原理:父子继承关系创建代理对象,原始类作为父类,代理类作为子类,这样既可以保证二者方法一致,同时在代理类中提供新的实现(额外功能+原始方法)

package jdkProxy;


import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import org.springframework.cglib.proxy.Proxy;

import java.lang.reflect.Method;

public class TestCGlib {
    public static void main(String[]args){
        //创建原始对象
        UserService userService=new UserService();
        //通过cglib方式创建动态代理对象
        //Proxy.newProxyInstance(); 不需要接口

        Enhancer enhancer = new Enhancer();
        enhancer.setClassLoader(TestCGlib.class.getClassLoader());
        enhancer.setSuperclass(UserService.class);//父类是原始对象
        MethodInterceptor interceptor = new MethodInterceptor() {
            @Override
            public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
                System.out.println("cglib 代理功能");
                Object result = method.invoke(userService,args);
                return result;
            }
        };
        enhancer.setCallback(interceptor);
        UserService userServiceProxy = (UserService) enhancer.create();
        userServiceProxy.login("zhangsan","123456");
    }
}

 总结

JDK动态代理 Proxy.newProxyInstance() 通过接口创建代理的实现类

Cglib动态代理 Enhancer

Spring工厂如何加工原始对象

 编码

package factory;

import org.springframework.beans.factory.config.BeanPostProcessor;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class ProxyBeanPostProcessor implements BeanPostProcessor {
    public Object postProcessBeforeInitialization(Object bean, String beanName) {
        return bean;
    }
    public Object postProcessAfterInitialization(Object bean, String beanName){

        InvocationHandler handler=new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("-----额外功能——-------");
                Object ret=method.invoke(bean,args);
                return ret;
            }
        };
        return Proxy.newProxyInstance(ProxyBeanPostProcessor.class.getClassLoader(),bean.getClass().getInterfaces(),handler);
    }

}


        <bean id="userService" class="factory.UserServiceImpl"></bean>
<!--
    1.实现配置BeanPostProcessor 进行加工
    2.配置文件中对BeanPostProcessor配置
-->     <bean id="proxyBeanPostProcessor" class="factory.ProxyBeanPostProcessor"></bean>

基于注解的AOP编程
1.基于注解的AOP编程开发步骤

  1. 1.原始对象
  2. 2.额外功能
  3. 3.切入点
  4. 4.组装切面

#通过切面类 定义了 额外功能@Around

                     定义了 切入点 @Around("execution *login(..)")

                     @Aspect 切面类

package aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;

@Aspect
/*
    1.额外功能
         public class MyArround implements MethodInterceptor {
            public Object invoke(MethodInvocation methodInvocation) throws Throwable
            {
                Obejct ret=methodInvocation.proceed();
                return ret;
            }
         }
    2.切入点
        <aop config
            <aop:pointcut id="" expression="execution(* *(..))"/>
 */
public class MyAspect {
    @Around("execution(* *(..))")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("around");
        Object ret=joinPoint.proceed();
        return ret;
    }
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">


    <aop:aspectj-autoproxy/>
    <bean id="userService" class="aspect.UserServiceImpl"></bean>
<!--
    1.额外功能
    2.切入点
    3.组装切面
-->
    <bean id="arround" class="aspect.MyAspect"></bean>

<!--    告知spring基于注解进行编程-->

</beans>

细节

切入点复用

切入点复用:在切面类中定义一个函数,上面@Pointcut注解,通过这种方式,定义切入点表达式,后面更有利于切入点复用

public class MyAspect {
    @Pointcut("execution(* *(..))")
    public void myPointcut(){};
    @Around(value = "myPointcut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("around");
        Object ret=joinPoint.proceed();
        return ret;
    }
    @Around(value = "myPointcut()")
    public Object around1(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("around1");
        Object ret=joinPoint.proceed();
        return ret;
    }
}

 动态代理 创建方式

AOP底层实现 2种代理创建方式

1.JDK 通过实现接口 新的实现 创建代理对象

2.Cglib通过继承父类 做新的子类 创建代理对象


默认情况 AOP编程 底层应用JDK动态代理创建方式

如果切换Cglib

1.基于注解AOP开发

        

<aop:aspectj-autoproxy proxy-target-class="true"/>

2.传统AOP开发

 <aop:config proxy-target-class="true">
<!--        所有的方法 都作为切入点 加入额外功能 login register-->
        <aop:pointcut id="pc" expression="execution(* *(..))"/>
        <aop:advisor advice-ref="arround" pointcut-ref="pc"></aop:advisor>
    </aop:config>

   

AOP开发中的坑

坑:同一个业务类中,进行业务方法间的相互调用 只有最外层方法,才是加入了额外功能(内部方法,通过普通方式调用,都调用的是原始方法) 如果想让内层方法也调用代理对象方法,ApplicationContextAware获得工厂,进而获得对象

package aspect;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

public class UserServiceImpl implements UserService, ApplicationContextAware {
    private ApplicationContext applicationContext;

    @Override
    public void login(String username, String password) {
        System.out.println("login");
    }

    @Override
    public void register(String username, String password) {
        System.out.println("register");
        UserService userService = applicationContext.getBean("userService", UserService.class);
        userService.login("zhangsan", "123456");
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext=applicationContext;
    }
}

AOP总结

相关文章:

  • C++中std::shuffle 的使用
  • MySQL 多列 IN 查询详解:语法、性能与实战技巧
  • 当 Selenium 的 click() /send_keys()等方法失效时:JavaScript 在 UI 自动化测试中的神奇用法
  • 工作记录 2017-02-06
  • gitlab 提交pr
  • 搭建Nginx
  • springboot第三站(1) web开发引入
  • Docker下载,包含Win、Mac
  • The test of the entire book_《Effective Modern C++》notes
  • Spring Boot集成PageHelper:轻松实现数据库分页功能
  • Linux系统之qrencode工具的安装与基本使用
  • 云安全相关博客阅读(四)
  • 使用静态库动态库也要头文件
  • 【Netty】消息分发处理方式
  • Unity shader管道液体流入并流出效果
  • Spring Boot 静态访问配置属性的解决方案
  • EditRocket for Mac v5.0.2 文本编辑器 支持M、Intel芯片
  • 从信息熵上看图像
  • RISCV虚拟化环境搭建
  • windows主机持久化技术
  • 总奖池超百万!第五届七猫现实题材征文大赛颁奖在即
  • 公安部部署“昆仑2025”专项工作,严打环食药等领域突出犯罪
  • 全球第七个迪士尼主题公园将落户阿布扎比
  • 中国人民银行:5月8日起降息,15日起降准
  • 中方对原产印度进口氯氰菊酯实施反倾销措施,商务部回应
  • 马上评|从一个细节看今年五一档电影