AOP底层实现原理、基于注解的AOP编程、AOP开发中的一个坑 打卡第八天

本文深入探讨了Java Spring中的AOP(面向切面编程)原理,包括JDK动态代理和CGlib动态代理的创建过程,分析了Spring工厂如何生成代理对象。同时,介绍了基于注解的AOP编程步骤和注意事项,揭示了AOP开发中的潜在问题及其解决方案。
摘要由CSDN通过智能技术生成

第五章、AOP底层实现原理

1. 核心问题

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

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

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

2. 动态代理的创建

2.1JDK的动态代理 (原理 + 编码)

1.Proxy.newProxyInstance方法参数详解

2.编码

public class TestJDKProxy {
    /*
    1.借类加载器  TestJDKProxy 或 UserServiceImpl 都可以
    2.JDK8.x 前必须加 final
     */
    public static void main(String[] args) {
        //1.创建原始对象
        UserServiceImpl userService = new UserServiceImpl();
        //2.JDK创建动态代理
        InvocationHandler handler = new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("---------proxy log----------");
                //原始方法运行
                Object ret = method.invoke(userService, args);
                return ret;
            }
        };
        UserService userServiceProxy =(UserService) Proxy.newProxyInstance(TestJDKProxy.class.getClassLoader(), userService.getClass().getInterfaces(), handler);
        userServiceProxy.register(new User());
        userServiceProxy.login("liulei","123456");
    }
}

2.2 CGlib的动态代理

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

CGlib编码

public class TestCGlib {
    public static void main(String[] args) {
        //1.创建原始对象
        UserService userService = new UserService();
        //2.通过CGlib的方式创建动态代理对象
        //对比JDK:Proxy.newProxyInstance(classloader,interfaces,invocationhandler)
        /*
         Enhancer.setClassLoader()
         Enhancer.setSuperClass()   等同interface
         Enhancer.setCallBack() ---> MethodInterceptor(cglib)    接口类型
         Enhancer.createProxy() ---> 创建代理对象
         */
        Enhancer enhancer = new Enhancer();
        enhancer.setClassLoader(TestCGlib.class.getClassLoader());
        enhancer.setSuperclass(userService.getClass());
        MethodInterceptor interceptor = new MethodInterceptor() {
            //等同InvocationHandler----invoke
            @Override
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                System.out.println("-----log------");
                Object ret = method.invoke(userService, args);
                return ret;
            }
        };
        enhancer.setCallback(interceptor);
        UserService userServiceProxy = (UserService)enhancer.create();
        userServiceProxy.login("liulei","13245");
        userServiceProxy.register(new User());
    }
}

总结

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

2.Cglib动态代理 Enhancer 通过继承父类创建代理的实现类

3.Spring工厂如何加工原始对象

思路分析

1f1acb77746d3ed44cf1722857f7e7bf.png

编码

public class ProxyBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }
    @Override
    /*
    Proxy.newProxyInstance();
     */
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        InvocationHandler handler = new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("---------log--------");
                Object ret= method.invoke(bean, args);
                return ret;
            }
        };
        return Proxy.newProxyInstance(ProxyBeanPostProcessor.class.getClassLoader(),bean.getClass().getInterfaces(),handler);
    }
}

配置文件

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

第六章、基于注解的AOP编程

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

1.原始对象

public interface UserService {
    void register(User user);
    boolean login(String name,String password);
}


public class UserServiceImpl implements UserService {
    
    @Override
    public void register(User user) {
        System.out.println("UserServiceImpl.register 业务运算 + DAO");
        // throw new RuntimeException("测试异常");
    }

    @Override
    public boolean login(String name, String password) {
        System.out.println("UserServiceImpl.login");
        return true;
    }
}

2.额外功能

3.切入点

4.组装切面

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

切入点 @Around(* login(..))

@Aspect 切面类

2.3.4都放在MyAspect类中完成

@Aspect
/*
  1. 额外功能
        public class MyAround implements MethodInterceptor {
            public Object invoke(MethodInvocation invocation) {
                Object ret = invocation.invoke();
                return ret;
            }
        }
        <bean id="around" class="com.liulei.dynamic.Around"/>

    2. 切入点
        <aop:config>
            <aop:pointcut id="pc" expression="execution(* login(..)))"/>
            <aop:advisor advice-ref="around" pointcut-ref="pc"/>
        </aop:config>
 */
public class MyAspect {
    @Around("execution(* login(..))")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable{
        System.out.println("-------------log-----------");
        Object ret = joinPoint.proceed();
        return ret;
    }
}

配置文件

<bean id="userService" class="com.liulei.aspect.UserServiceImpl"/>
<!--    切面-->
<!--    1.额外功能-->
<!--    2.切入点-->
<!--    3.组装切面-->
<bean id="around" class="com.liulei.aspect.MyAspect"/>

<!--    告知Spring基于注解来进行aop编程-->
<aop:aspectj-autoproxy/>
</beans>

2.细节

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

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

    @Around(value = "myPointcut()")
    public Object around1(ProceedingJoinPoint joinPoint) throws Throwable{
        System.out.println("-------------logty-----------");
        Object 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:config>

第七章、AOP开发中的一个坑

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

public class UserServiceImpl implements UserService, ApplicationContextAware {
   private ApplicationContext ctx;
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.ctx = applicationContext;
    }
    @Log
    @Override
    public void register(User user) {
        System.out.println("UserServiceImpl.register 业务运算 + DAO");
        // throw new RuntimeException("测试异常");
        //this.login("liulei","123465");
        /*
         this.login("liulei","123465"); 这么写调用的是本类的 login 方法, 即原始对象的 login 方法
         为什么不在这里创建一个工厂获取代理对象呢?
         Spring的工厂是重量级资源, 一个应用中应该只创建一个工厂.
        因此我们必须通过 ApplicationContextAware 拿到已经创建好的工厂
         */
        UserService userService = (UserService)ctx.getBean("userService");
        userService.login("liulei","123456");
    }
    @Override
    public boolean login(String name, String password) {
        System.out.println("UserServiceImpl.login");
        return true;
    }

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值