Spring学习笔记:详解AOP编程

Spring笔记汇总

AOP编程

1、AOP的概念

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

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

  • 切面 = 切入点 + 额外功能

OOP (Object Oritened Programing)【面向对象编程Java】

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

POP (Producer Oriented Programing) 【面向过程(方法、 函数)编程C】

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

AOP的概念:

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

好处:利于原始类的维护

注意:AOP编程不可能取代OOP ,是OOP编程的有益补充。

2、AOP编程的开发步骤

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

3、切面的名词解释

切面 = 切入点 + 额外功能

几何学:面 = 点 + 相同的性质

在这里插入图片描述

动态代理类的创建

1、JDK的动态代理

  • Proxy.newProxyInstance 方法参数详解
    在这里插入图片描述
    在这里插入图片描述

  • 编码

    public class TestJDKProxy {
    
        /**
         *  用于测试:测试JDK代理对象
         *
         */
        @Test
        public void test(){
            
            /*
            1.借用类加载器		TestJDKProxy
            					UserServiceImpl
            2. JDK8.0前
            		final UserService userService = new UserServiceImpl();
            */
    
            // 创建原始对象
            UserService userService = new UserServiceImpl();
    
            // JDK创建动态代理
    
    //        InvocationHandler hander = new InvocationHandler() {
    //            @Override
    //            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
      				......
    //            }
    //        };
            InvocationHandler hander = (proxy, method, args) -> {
                System.out.println("---log---");
                Object ret = method.invoke(userService, args);
                return ret;
            };
    
            UserService userServiceProxy = (UserService) Proxy.newProxyInstance(TestJDKProxy.class.getClassLoader(), userService.getClass().getInterfaces(), hander);
            userServiceProxy.login("你好", "123456");
            userServiceProxy.register(new User());
    
        }
    }
    

2、CGlib的动态代理

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

在这里插入图片描述

public class TestCglibProxy {
    public static void main(String[] args) {
        // 创建原始对象
        UserService userService = new UserService();

        /*
        2通过cglib方式创建动态代理对象
        Proxy.newProxyInstance(classloader, interface, invocationHandler)

        对比:
        Enhancer.setClassLoader()
        Enhancer.setSuperClass()
        Enhancer.setCallback(); ---> MethodInterceptor(cglib)
        Enhancer.create() ---> 代理
        */

        Enhancer enhancer = new Enhancer();

        enhancer.setClassLoader(TestCglibProxy.class.getClassLoader());
        enhancer.setSuperclass(userService.getClass());

        MethodInterceptor interceptor = new MethodInterceptor() {
            @Override
            public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
                System.out.println("---log---");
                Object invoke = method.invoke(userService, args);
                return invoke;
            }
        };

        enhancer.setCallback(interceptor);

        UserService userService1Proxy = (UserService) enhancer.create();
        userService1Proxy.login("我","45");
        userService.register(new User());

    }
}

总结

  1. JDK动态代理 Proxy.newproxyInstance() 通过接口创建代理的实现类
  2. Cglib动态代理Enhancer通过继承父类创建的代理类
  3. JDK和CGLIB动态代理区别

4、Spring工厂如何加工原始对象

  • 思路分析
    在这里插入图片描述

  • 编码

    public class MyBeanPostProcessor implements BeanPostProcessor {
    
        @Override
        public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
            return bean;
        }
    
        @Override
        public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    
            InvocationHandler hander = (proxy, method, args) -> {
                System.out.println("---log---");
                Object invoke = method.invoke(bean, args);
                return null;
            };
    
            return Proxy.newProxyInstance(MyBeanPostProcessor.class.getClassLoader(),bean.getClass().getInterfaces(),hander);
        }
    }
    
    <bean id="userService" class="com.company.factory.UserServiceImpl"/>
    
    <!--
        1. 实现BeanPostProcessor进行加工
        2.配置文件中对BeanPostProcessor进行配置
        -->
    
    <bean id="myBeanPostProcessor" class="com.company.factory.MyBeanPostProcessor"/>
    

基于注解的AOP编程

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

  • 原始对象

  • 额外功能

  • 切入点

  • 组装切面

    #通过切面类  定义了 额外功能 @Around
                定义了 切入点   @Around("execution(* login(..))")
                @Aspect切面类
    
    package com.company.aspect;
    
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    
    /*
        之前:
    
        1.额外功能
            public class MyAround implements MethodInterceptor{
    
                public Object invoke(MethodInvocation invocation){
                    Object ret  = invocation.proceed();
    
                   return ret;
                }
            }
        2.切入点
            <aop:config
                <aop:pointcut id="" expression="execution(* login(..))"/>
     */
    @Aspect
    public class MyAspect {
    
        @Around("execution(* login(..))")
        public Object around(ProceedingJoinPoint joinPoint){
            System.out.println("--- aspect log ---");
            Object ret = null;
            try {
                ret = joinPoint.proceed();
            } catch (Throwable throwable) {
                throwable.printStackTrace();
            }
    
            return ret;
        }
    
    }
    
        <bean id="userService" class="com.company.aspect.UserServiceImpl"/>
    
        <!--
            切面
                1.额外功能
                2.切入点
                3.组装切面
        -->
        <bean id="aspect" class="com.company.aspect.MyAspect"/>
    
    	<!--通知Spring基于注解进行AOP编程-->
        <aop:aspectj-autoproxy/>
    

2、细节

1. 切入点复用

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

@Aspect
public class MyAspect {

    @Pointcut("execution(* login(..))")
    public void myPointCut() {
    }

    @Around(value = "myPointCut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("--- aspect log ---");
        Object ret = null;
        ret = joinPoint.proceed();

        return ret;
    }

    @Around(value = "myPointCut()")
    public Object around1(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("--- aspect log ---");
        Object ret = null;
        ret = joinPoint.proceed();

        return ret;
    }

}

2. 动态代理的创建方式

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"></aop>

AOP开发中的注意点

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

@Pointcut("execution(* *..UserService..*(..))")
public void myPointCut() {
}


package com.company.aspect;

import com.company.proxy.User;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

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

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

    @Override
    public void login(String name, String password) {
        System.out.println("UserServiceImpl.login");
        //调用的是原始对象的login方法-- ->核心功能
        /*
        设计目的:代理对象的login方法--->额外功能+核心功能
                AppliCationContext ctx = new ClassPathXmlApplicationContext("/applicationContext.xml");
                UserService userService = (UserService) ctx . getBean("userService");
                userService.login();
        不行:Spring工厂重量级资源一个应用中应该只创建一个工厂
        */
//        this.register(new User());
        UserService userService = (UserService) ctx.getBean("userService");
        userService.register(new User());
    }

    @Override
    public void register(User user) {
        System.out.println("UserServiceImpl.register");
    }

}

AOP阶段知识总结

在这里插入图片描述

持久层整合

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值