手写一个Spring AOP及Spring AOP代理的底层解析和两种代理模式

手写一个Spring AOP

1、声明AspectJ风格的AOP的支持—配置类上添加@EnableAspectJAutoProxy注解。
在这里插入图片描述
2、声明一个切面—定义一个切面类,并添加@Aspect注解,并在该切面类下声明切点和通知。
在这里插入图片描述
参照: https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#aop.
一个简单的AOP就完成了,下面定义一个测试类测试一下效果:
在这里插入图片描述
在这里插入图片描述
可以看到,在执行service真实逻辑之前,先执行了before通知的方法。

但是,值得一提的是通过AnnotationConfigApplicationContext容器获得的IndexService bean不是原来的bean了,而是aop的代理对象。

Spring AOP代理的底层解析

那么aop是在什么时候完成了代理呢?
在我的另一篇博客(Spring Bean初始化的底层原理)的最后讲到spring是在doCreateBean()方法里完成创建bean的实例、属性注入的:
在这里插入图片描述
在这里插入图片描述

initializeBean()方法里会执行生命周期初始化回调方法并完成aop代理:
(注意:spring支持多种生命周期回调机制,执行顺序如下图所示,对应底层源码1、2、3)
在这里插入图片描述
在这里插入图片描述
—画重点—
因此,aop代理是在执行生命周期初始化回调方法之后的,具体顺序为:
创建bean的实例—>属性注入—>init-method生命周期初始化回调方法—>aop代理—>bean放入二级缓存

注意!!!
代理的主要作用是对原有的功能的增强。
spring aop有二种代理模式,一种是基于JDK动态代理,一种是基于cglib代理:

1、当类实现了接口时(此处UserDaoImpl实现了接口UserDao),默认使用JDK动态代理:

public static void Test1(){
		final UserDao userDao = new UserDaoImpl();
		// newProxyInstance的三个参数解释:
		// 参数1:代理类的类加载器,同目标类的类加载器
		// 参数2:代理类要实现的接口列表,同目标类实现的接口列表
		// 参数3:回调,是一个InvocationHandler接口的实现对象,当调用代理对象的方法时,执行的是回调中的invoke方法
		//proxy为代理对象
		UserDao proxy = (UserDao) Proxy.newProxyInstance(userDao.getClass().getClassLoader(),
				userDao.getClass().getInterfaces(), new InvocationHandler() {

					@Override
					// 参数proxy:被代理的对象
					// 参数method:执行的方法,代理对象执行哪个方法,method就是哪个方法
					// 参数args:执行方法的参数
					public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
						System.out.println("proxy---new fuction");
						Object result = method.invoke(userDao, args);
						return result;
					}
				});
		//代理对象执行方法
		proxy.saveDao();
	}

代码执行结果如下;
在这里插入图片描述
2、当类没有实现接口时,此时是cglib代理(UserDaoImpl类没有实现接口),实际上是生成了目标类的子类来增强:

public static void Test2() {
		final UserDaoImpl userDao=new UserDaoImpl();
		// 创建cglib核心对象
		Enhancer enhancer = new Enhancer();
		// 设置父类
		enhancer.setSuperclass(userDao.getClass());
		// 设置回调
		enhancer.setCallback(new MethodInterceptor() {
			/**
			 * 当你调用目标方法时,实质上是调用该方法
			 * intercept四个参数:
			 * proxy:代理对象
			 * method:目标方法
			 * args:目标方法的形参
			 * methodProxy:代理方法
			 */
			@Override
			public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy)
					throws Throwable {
				System.out.println("cglib proxy---new function");
				Object result = method.invoke(userDao, args);
				return result;
			}
		});
		// 创建代理对象
		UserDaoImpl proxy = (UserDaoImpl) enhancer.create();
		proxy.saveDao();
	}

代码执行结果如下:
在这里插入图片描述

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值