一、AOP编程(面向切面编程)
AOP的本质是代理。
1、静态代理设计模式
概念:通过代理类为原始类增加额外功能。
代理类 = 原始类 + 额外功能 +实现原始类的相同接口。
优点:避免原始类因为额外功能频繁被修改,从而使代码更加利于维护。
缺点:a、代理类数量过多,不利于管理项目。
b、额外功能代码冗余。
c、替换代理的额外功能很麻烦。
2、Spring的动态代理设计模式(AOP)
a、导入jar包:aopallaince.jar和aspectjwave.jar
b、创建原始对象
原始对象只有核心功能,没有额外功能。
c、创建额外功能
按照需求实现以下接口(均实现了父接口Advice):
(1)MethodBeforeAdvice
//额外功能在原始方法之前运行
public class MyInterceptor implements MethodBeforeAdvice { @Override public void before(Method method, Object[] args, Object target) throws Throwable { //参数:method--原始方法,args--原始方法的参数,target--原始对象
//添加额外功能 method.invoke(args, target); } }
(2)AfterReturningAdvice
//额外功能在原始方法之后运行 public class MyInterceptor implements AfterReturningAdvice { @Override public void afterReturning(Object ret, Method method, Object[] args, Object target) throws Throwable { method.invoke(ret, args); //ret--原始方法的返回值,参数:method--原始方法,args--原始方法的参数,target--原始对象
//添加额外功能 } }
(3)MethodInterceptor
//原始方法之前之后都有额外功能
public class Intercepter implements MethodInterceptor { @Override public Object invoke(MethodInvocation mi) throws Throwable { //参数:mi--原始方法
//添加额外功能 Object obj = mi.proceed(); //添加额外功能
//返回值Object:原始方法的返回值 return obj; } }
(4)ThrowsAdvice
额外功能在原始方法抛出异常时执行。
d、定义切入点pointcut
设置额外功能加入的位置。
切入点函数execution():
<aop:pointcut id="pc" expression="execution(* *(..))">
(1)方法切入点
execution()
切入点表达式 * *(..)
第一个*表示方法的返回值,第二个*表示方法名,(..)表示方法的参数。eg:
* login(String) 表示名叫login的只有一个字符串参数的方法。
(2)类切入点
execution()
切入点表达式 * *.类名.*(..)
第一个*表示方法的返回值,第二个*表示该类的包名,第二个*表示方法名,(..)表示方法的参数。eg:
* *.UserServiceImpl.*(..) 表示UserServiceImpl类。
(3)包切入点
execution()
切入点表达式 * 包名.*.*(..)支持当前包中的类,不包括包中子类,* 包名..*.*(..)支持包中子类
第一个*表示方法的返回值,第二个*表示类名,第三个*表示方法名,(..)表示方法的参数。
切入点函数args():
<!--此切入点函数只专注于方法的参数--> <aop:pointcut id="pc" expression="args(..)">
切入点函数within():
<!--此切入点函数针对包和类作为切入点--> <aop:pointcut id="pc" expression="within(*.UserServiceimpl.*)"/>
切入点函数@annotation():
<!--此切入点针对注解进行切入--> <aop:potintcut id="pc" @annotation(dynamicproxy.Log)/>
切入点函数可以进行逻辑运算:and or not。
e、组装 切入点+额外功能
<!--配置额外功能类--> <bean id="before" class="xxx.xxx.MyInterceptor"/> <!--组装切面--> <aop:advisor pointcut-ref="pc" advice-ref="before"/>
通过原始类的id获得代理对象,通过原始类的接口接受代理对象。
二、AOP的实现原理:
AOP=代理+BeanPostProcessor(后置处理Bean)
1、原始JDK的动态代理技术(基于接口)
a、类加载器
b、原始对象所实现的接口
c、额外功能InvacationHandler
pubic class TestJDKProxy{ @Test public void test(){ final UserService us = new UserServiceImpl(); //调用JDKProxy的方法 //1、使用Classloader //2、原始对象所实现的接口 //3、额外功能InvocationHandler InvocationHandler hi = new InvocationHandler(){ // method:原始方法 // args:原始方法的参数 // 返回值:原始方法的返回值 public Object invoke(Object proxy,Method method,Object[] args)throws Throwable{ //添加额外功能 Object ret = method.invoke(us,args); return ret; } }; UserService usp = (UserService)Proxy.newProxyInstance(UserServiceImpl.class.getClassLoader(),us.getClass.getInterfaces(),hi); //usp即为代理对象 usp.login("zhangsan","123456"); } }
2、cglib动态字节码增加技术完成(基于继承的方式)
public class TestCglibProxy{ @Test public void test(){ final AdminService as = new AdminServiceImpl(); Enhancer enhancer = new Enhancer(); //设置父类 enhancer.setSuperclass(os.getClass); //创建额外功能 InvocationHander hi = new InvocationHander(){ public Object invoke(Object proxy,Method method,Object[] args)throws Throwable{ //添加额外功能 Object ret = method.invoke(as,args); } }; //设置额外功能 enhancer.setCallback(hi); //创建代理类 AdminService asp = (AdminService)enhancer.creat(); asp.login(admin); } }
3、BeanPostProcessor示例图