Spring AOP(一)-AOP的底层实现原理

一、AOP的概念和原理

AOP(Aspect-Oriented Programming):面向切面编程,是一种新的方法论,切面能够帮助我们模块化横切关注点,简言之,横切关注点可以被描述为影像应用多出的功能,列入安全就是一个横切关注点,应用中的许多方法都涉及到安全规则,如下图所示:

对传统OOP(Ojected-Oriented Programming)的补充和完善.
切面的优点:
• 每个关注点度集中在一个地方,而不是分散到多处代码中
• 服务模块更简洁,因为他们只包含主要关注点,(或者核心功能)的代码,而次要关注点的代码被转移到切面中了.
• 实现了业务逻辑和系统级的服务进行隔离,使得业务逻辑和系统级的服务耦合度降低 ,从而提高系统的重用性和开发效率.

名词解释:
业务逻辑: 某个类的某个方法本身要实现的功能。
系统级的服务: 系统的日志、事务、权限验证。

二、如何实现AOP(底层实现原理)

每个动态代理类度必须实现,InvocationHandler这个接口,并且每个代理类的实列都关联到了一个handler当我们通过一个代理类调用一个方法的时候,我们方法的调用就会被转发为由InvocationHandler这个接口的invoke方法来调用,invoke是唯一的唯一的方法.
主要有两种方法:jdk的动态代理和cglib的动态代理

1.  jdk动态代理(利用java的反射思想)

JDK的动态代理主要涉及到java.lang.reflect包中的两个类:Proxy和InvocationHandler。其中InvocationHandler是一个接口,可以通过实现该接口定义横切逻辑,在并通过反射机制调用目标类的代码,动态将横切逻辑和业务逻辑编织在一起。

首先编写IUserDao接口编写两个方法

package com.dqsy.spring.proxy;

public interface IUserDao {
	
	public void addUser();
	public void serchUser();
}
实现这个接口的方法

package com.dqsy.spring.proxy.impl;

import com.dqsy.spring.proxy.IUserDao;

public class IUserDaoImpl implements IUserDao {

	@Override
	public void addUser() {
		System.out.println("添加方法....");
	}
	@Override
	public void serchUser() {
		// TODO Auto-generated method stub
		System.out.println("寻找方法....");
	}

}

创建测试类

package com.dqsy.spring.test;

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

import org.junit.Test;

import com.dqsy.spring.proxy.IUserDao;
import com.dqsy.spring.proxy.impl.IUserDaoImpl;

public class AopTest {
	/**
	 * 常规的调用
	 */
	@Test
	public void test(){
		IUserDao userDao = new IUserDaoImpl();
		userDao.serchUser();
	}
	/**
	 * JDk动态代理方法
	 */
	@Test
	public void proxytest(){
		//实列化目标对象
		IUserDao target = new IUserDaoImpl();
		IUserDao proxy = ((IUserDao) Proxy.newProxyInstance(
				//目标类ClassLoad定义了有那个ClassLoad对象生成代理进行加载
				target.getClass().getClassLoader(),
				//目标类的接口,一个interface接口,表示我们将为我们的代理对象提供一组接口,如果我们吗提供一组接口给它
				//那么代理就宣称实现该接口(多态)这样我们就调用该接口中的方法了
				target.getClass().getInterfaces(),
				//匿名内部类
				new InvocationHandler(){
					/**
					 * proxy:指我们要代理的那个真实对象
					 * method:指我们要调用真是对象的方法的method对象
					 * params:指我们要调用真是方法的参数
					 */
					@Override
					public Object invoke(Object proxy, Method method, Object[] params) throws Throwable {
						// TODO Auto-generated method stub
						System.out.println("添加方法...");
						System.out.println(""+method.getName());
						Object result = method.invoke(target, params);
						System.out.println("编写日志...");
						return result;
					}
					
				}));
		proxy.serchUser();
		
	}
}
结果如下:

那么另一个方法结果又是怎样呢?

以上方法就是在没有用spring的知识,而实现aop思想的.

2.cglib动态代理

 使用JDK创建代理有一个限制,即它只能为接口创建代理,这一点我们从Proxy的接口方法newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)就看得很清楚,第三个入参interfaces就是为代理实例指定的实现接口。虽然,面向接口的编程被很多很有影响力人(包括Rod Johnson)的推崇,但在实际开发中,开发者也遇到了很多困惑:难道对一个简单业务表的操作真的需要创建5个类(领域对象类、Dao接口,Dao实现类,Service接口和Service实现类)吗?对于这一问题,我们还是留待大家进一步讨论。现在的问题是:对于没有通过接口定义业务方法的类,如何动态创建代理实例呢?JDK的代理技术显然已经黔驴技穷,CGLib作为一个替代者,填补了这个空缺。

 CGLib采用非常底层的字节码技术,可以为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,并在拦截方法相应地织入横切逻辑。

小结:

 Spring AOP在底层就是利用JDK动态代理或CGLib动态代理技术为目标Bean织入横切逻辑。在这里,我们对以上两节动态创建代理对象做一个小结。

在PerformaceHandler和CglibProxy中,有三点值得注意的地方是:第一,目标类的所有方法都被添加了性能监视横切的代码,而有时,这并不是我们所期望的,我们可能只希望对业务类中的某些方法织入横切代码;第二,我们手工指定了织入横切代码的织入点,即在目标类业务方法的开始和结束前调用;第三,我们手工编写横切代码。以上三个问题,在AOP中占用重要的地位,因为Spring AOP的主要工作就是围绕以上三点展开:Spring AOP通过Pointcut(切点)指定在哪些类的哪些方法上施加横切逻辑,通过Advice(增强)描述横切逻辑和方法的具体织入点(方法前、方法后、方法的两端等),此外,Spring还通过Advisor(切面)组合Pointcut和Advice。有了Advisor的信息,Spring就可以利用JDK或CGLib的动态代理技术为目标Bean创建织入切面的代理对象了。

JDK动态代理所创建的代理对象,在JDK 1.3下,性能强差人意。虽然在高版本的JDK中,动态代理对象的性能得到了很大的提高,但是有研究表明,CGLib所创建的动态代理对象的性能依旧比JDK的所创建的代理对象的性能高不少(大概10倍)。而CGLib在创建代理对象时性能却比JDK动态代理慢很多(大概8倍),所以对于singleton的代理对象或者具有实例池的代理,因为不需要频繁创建代理对象,所以比较适合用CGLib动态代理技术,反之适合用JDK动态代理技术。此外,由于CGLib采用生成子类的技术创建代理对象,所以不能对目标类中的final方法进行代理。







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

奋斗的小巍

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值