Spring源码学习-5.AOP原理分析

1.AOP概述

AOP是Aspect-Oriented Programming 面向切面编程的简称
在Spring AOP的实现中,使用的是java本身的语言特性,如java proxy代理类,拦截器技术来实现AOP编织,AOP与IoC结合使用,为Spring本身和应用程序开发提供了很好的帮助
spring AOP中封装AspectJ 这个一优秀的AOP解决方案
下面我们将对aop的原理进行分析

 1.Advice通知

通知类型有5种,
Before
After
After-return 
After-throwing
throwing
Advice通知定义在连接点做什么,为切面增强提供植入接口
有BeforeAdvice,AfterAdvice和ThrowsAdvice
BeforeAdvice的常用接口MethodBeforeAdvice前置增强接口,使用这个接口需要实现一个方法,
public void before(Method method, Object[] args, Object target)
AfterAdvice常用接口AfterReturningAdvice也需要实现一个方法
public void afterReturning(Object returnValue, Method method,
Object[] args, Object target) throws Throwable {
ThrowsAdvice不需要实现方法

public class CountingBeforeAdvice extends MethodCounter implements MethodBeforeAdvice {  
    //实现方法前置通知MethodBeforeAdvice接口的方法  
    public void before(Method m, Object[] args, Object target) throws Throwable {  
    //以目标对象方法作为参数,调用父类MethodCounter的count方法统计方法调用次数  
        count(m);  
    }  
}  
CountingBeforeAdvice的父类MethodCounter的源码如下:  
public class MethodCounter implements Serializable {  
    //方法名—>方法调用次数的map集合,存储方法的调用次数  
    private HashMap<String, Integer> map = new HashMap<String, Integer>();  
    //所有方法的总调用次数  
    private int allCount;  
    //统计方法调用次数,CountingBeforeAdvice的调用入口  
    protected void count(Method m) {  
        count(m.getName());  
    }  
    //统计指定名称方法的调用次数  
    protected void count(String methodName) {  
        //从方法名—>方法调用次数集合中获取指定名称方法的调用次数  
        Integer i = map.get(methodName);  
//如果调用次数不为null,则将调用次数加1,如果调用次数为null,则设置调用次数为1  
        i = (i != null) ? new Integer(i.intValue() + 1) : new Integer(1);  
        //重新设置集合中保存的方法调用次数  
        map.put(methodName, i);  
        //所有方法总调用次数加1  
        ++allCount;  
    }  
    //获取指定名称方法的调用次数  
    public int getCalls(String methodName) {  
        Integer i = map.get(methodName);  
        return (i != null ? i.intValue() : 0);  
    }  
    //获取所有方法的总调用次数  
    public int getCalls() {  
        return allCount;  
    }  
    public boolean equals(Object other) {  
        return (other != null && other.getClass() == this.getClass());  
    }  
    public int hashCode() {  
        return getClass().hashCode();  
    }  


2.PointCut切点

切点决定Advice通知应该作用于那个连接点,通过PointCut来定义需要增强的方法集合

以正则表达式切点JdkRegexpMethodPointcut为例,来了解PointCut的工作原理
在matches(String pattern, int patternIndex);这个方法中实现了用正则表达式进行解析的过程

public class JdkRegexpMethodPointcut extends AbstractRegexpMethodPointcut {  
    //要编译的正则表达式模式  
    private Pattern[] compiledPatterns = new Pattern[0];  
    //编译时要排除的正则表达式模式  
    private Pattern[] compiledExclusionPatterns = new Pattern[0];  
//将给定的模式字符串数组初始化为编译的正则表达式模式  
    protected void initPatternRepresentation(String[] patterns) throws PatternSyntaxException {  
        this.compiledPatterns = compilePatterns(patterns);  
    }  
//将给定的模式字符串数组初始化为编译时要排除的正则表达式模式  
    protected void initExcludedPatternRepresentation(String[] excludedPatterns) throws PatternSyntaxException {  
        this.compiledExclusionPatterns = compilePatterns(excludedPatterns);  
    }  
//使用正则表达式匹配给定的名称  
    protected boolean matches(String pattern, int patternIndex) {  
        Matcher matcher = this.compiledPatterns[patternIndex].matcher(pattern);  
        return matcher.matches();  
    }  
    //使用要排除的正则表达式匹配给定的名称  
    protected boolean matchesExclusion(String candidate, int patternIndex) {  
        Matcher matcher = this.compiledExclusionPatterns[patternIndex].matcher(candidate);  
        return matcher.matches();  
    }  
//将给定的字符串数组编译为正则表达的模式  
    private Pattern[] compilePatterns(String[] source) throws PatternSyntaxException {  
        Pattern[] destination = new Pattern[source.length];  
        for (int i = 0; i < source.length; i++) {  
            destination[i] = Pattern.compile(source[i]);  
        }  
        return destination;  
    }  
}  



3.Advisor通知器

完成advice和PointCut后,需要一个对象将他们整合起来,这个就是通知器

通知器的实现在DefaultPointCutAdvisor中.

public class DefaultPointcutAdvisor extends AbstractGenericPointcutAdvisor implements Serializable {  
    //默认切入点  
//Pointcut.TRUE在切入点中的定义为:Pointcut TRUE = TruePointcut.INSTANCE;  
    private Pointcut pointcut = Pointcut.TRUE;  
//无参构造方法,创建一个空的通知器  
    public DefaultPointcutAdvisor() {  
    }  
    //创建一个匹配所有方法的通知器  
    public DefaultPointcutAdvisor(Advice advice) {  
        this(Pointcut.TRUE, advice);  
    }  
    //创建一个指定切入点和通知的通知器  
    public DefaultPointcutAdvisor(Pointcut pointcut, Advice advice) {  
        this.pointcut = pointcut;  
        setAdvice(advice);  
    }  
    //为通知设置切入点  
    public void setPointcut(Pointcut pointcut) {  
        this.pointcut = (pointcut != null ? pointcut : Pointcut.TRUE);  
    }  
    //获取切入点  
    public Pointcut getPointcut() {  
        return this.pointcut;  
    }  
    public String toString() {  
        return getClass().getName() + ": pointcut [" + getPointcut() + "]; advice [" + getAdvice() + "]";  
    }  
}  

TruePointcut 作用通知器默认的切入点,其主要功能是配置默认的类过滤器和方法匹配器,即定义 Spring AOP 对于哪些类的哪些方法其作用,源码如下
class TruePointcut implements Pointcut, Serializable {  
    //INSTANCE是TruePointcut类的一个常量单件,即整个应用中只有这个一个,  
//不会创建第二个实例对象,确保该实例对象的唯一性,单态模型  
    public static final TruePointcut INSTANCE = new TruePointcut();  
    //单态模式构造方法  
    private TruePointcut() {  
    }  
    //获取切入点的类过滤器  
    public ClassFilter getClassFilter() {  
        return ClassFilter.TRUE;  
    }  
    //获取切入点的方法匹配器  
    public MethodMatcher getMethodMatcher() {  
        return MethodMatcher.TRUE;  
    }  
    //获取单态模式对象的方法  
    private Object readResolve() {  
        return INSTANCE;  
    }  
    public String toString() {  
        return "Pointcut.TRUE";  
    }  
}  

2.Aop设计与实现

1.AOP中核心技术是动态代理

目前Java开发包中包含了对动态代理的支持,但是其实现只支持对接口的的实现。 其实现主要通过java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口。 

Proxy类主要用来获取动态代理对象,InvocationHandler接口用来约束调用者实现

动态代理实例代码


package day20150810;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyDemo {
	public static void main(String[] args) {
		Demo demo = new Demo();
		demo.run();
		((Face) Proxy.newProxyInstance(Demo.class.getClassLoader(),
				Demo.class.getInterfaces(), new ProxyTest(demo))).run();
	}
}
interface Face{
	void run();
}
class Demo implements Face{
	public void run(){
		System.out.println("Run~~");
	}
}
class ProxyTest implements InvocationHandler{
	private Object object;
	public ProxyTest(Object object) {
		super();
		this.object = object;
	}
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		System.out.println("Proxy~~");
		System.out.println("Method name:"+method.getName());
		Object result = null;
        //调用之前
         System.out.println("Before~~~~");
        //调用原始对象的方法
         result=method.invoke(object, args);
        //调用之后
         System.out.println("After~~~~");
         return result;
	}
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
YOLO高分设计资源源码,详情请查看资源内容中使用说明 YOLO高分设计资源源码,详情请查看资源内容中使用说明 YOLO高分设计资源源码,详情请查看资源内容中使用说明 YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值