本篇博客知识点
1.SpringAOP一些概率理解
2.SpringAOP底层拦截的—java代码方式实现
3.SpringAOP底层拦截的—XML方式实现
SpringAOP一些概率理解
- 面向切面编程:Aspect Oriented Programming,可以通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术
- AOP可以说是OOP(面向对象编程)的补充和完善。在OOP设计中有可能导致代码的重复不利于模块的重用性,例如日志功能。日志代码往往水平地散布在所有对象层次中,而与它所散布到的对象的核心功能关系不大。但是在OOP中这些业务要和核心业务代码在代码这一级集成。还有些如安全性、事务等也是如此。能不能把这些与核心业务无关但系统中需要使用的业务(称为切面)单独编写成一个模块,在主要核心业务代码中不调用,而是在配置文件中做些配置,配置核心业务需要使用到得切面部分,在系统编译时才织入到业务模块中。
切面(Aspect):
简单的理解就是把那些与核心业务无关的代码提取出来,进行封装成一个或几个模块用来处理那些附加的功能代码。(如日志,事务,安全验证)我们把这个模块的作用理解为一个切面,其实切面就是我们写一个类,这个类中的代码原来是在业务模块中完成的,现在单独成一个或几个类。在业务模块需要的时候才织入。
连接点(Joinpoint):
在程序执行过程中某个特定的点,比如某方法调用的时候或者处理异常的时候。 在Spring AOP中,一个连接点总是代表一个方法的执行。通过声明一个JoinPoint类型的参数可以使通知(Advice)的主体部分获得连接点信息。
切入点(Pointcut):
本质上是一个捕获连接点的结构。在AOP中,可以定义一个pointcut,来捕获相关方法的调用
织入(Weaving):把切面(aspect)连接到其它的应用程序类型或者对象上,并创建一个被通知(advised)的对象。 这些可以在编译时,类加载时和运行时完成。Spring和其它纯Java AOP框架一样,在运行时完成织入。
通知(Advice):在切面的某个特定的连接点(Joinpoint)上执行的动作。通知有各种类型,其中包括“around”、“before”和“after”等通知。 通知的类型将在后面部分进行讨论。许多AOP框架,包括Spring,都是以拦截器做通知模型,并维护一个以连接点为中心的拦截器链。
SpringAOP底层拦截代码实例—v1版本
Spring所需要的包
Spring 代理拦截实现代码— Java方式
被拦截对象Person.java
/**
* @author<a href="mailto:953801304@qq.com">胡龙华</a>
*/
public class Person {
public void run(){
System.out.println("I'm running!");
}
public void Hello(){
System.out.println("Hello,Spring!");
}
}
拦截实例代码
package cn.hncu2.v1;
import org.aopalliance.aop.Advice;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.junit.Test;
import org.springframework.aop.Advisor;
import org.springframework.aop.framework.ProxyFactoryBean;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.aop.support.JdkRegexpMethodPointcut;
/**
* @author<a href="mailto:953801304@qq.com">胡龙华</a>
*/
public class demo1 {
@Test
public void t1(){
//切面=切点+通知 Advisor = cut + advice
// 1.创建一个原型对象
Person p = new Person();
// 2.实现代理类工厂
ProxyFactoryBean factory = new ProxyFactoryBean();
//3.实现原型对象,代理目标
factory.setTarget(p);
//4.声明切点:就是说你要来拦截原型对象的哪些方法
JdkRegexpMethodPointcut pointcut = new JdkRegexpMethodPointcut();
//5.设置切点的正则:用正则表达式来设置拦截所有带run的方法
pointcut.setPattern(".*run.*");
//6.定义通知: 设定方法执行前栏、还是后栏还是都拦截(环绕栏)
Advice advice = new MethodInterceptor() {
//环绕栏
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("前面拦拦");
Object obj = invocation.proceed();
System.out.println("后面拦截");
return obj;
}
};
//7.声明切面 : Advisor = pointcut + advice
Advisor advisor = new DefaultPointcutAdvisor(pointcut, advice);
//8.把切面设置到代理工厂里:进厂子干活
factory.addAdvisor(advisor);
//9.代理工厂生产代理后的对象
Person p2 = (Person) factory.getObject();
p2.run();
p2.Hello();
}
}
测试:执行结果,只拦截了run方法
Spring 代理拦截实现代码— XML方式
将上面的拦截方法用XML方式来实现~
我先把两种方式代码用图的显示比较显示
好像有点看不清,我把两种图都贴上
Java方式
XML方式
v1.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
">
<!-- 1.创建一个原型对象-->
<bean id="p" class="cn.hncu2.v1.Person"/>
<!-- 2.实现代理类工厂 -->
<bean id="factory" class="org.springframework.aop.framework.ProxyFactoryBean">
<!-- 3.实现原型对象,代理目标 -->
<property name="target" ref="p"/>
<!-- 8.把切面设置到代理工厂里:进厂子干活 -->
<property name="interceptorNames">
<list> <value>advisor</value> </list>
</property>
</bean>
<!-- 4.声明切点:就是说你要来拦截原型对象的哪些方法 -->
<bean id="pointcut" class="org.springframework.aop.support.JdkRegexpMethodPointcut">
<!-- 5.设置切点的正则:用正则表达式来设置拦截所有带run的方法 -->
<property name="pattern" value=".*run.*"/>
</bean>
<!-- 6.定义通知: 设定方法执行前栏、还是后栏还是都拦截(环绕栏) -->
<!-- 因为Java是实习的是匿名内部类,那么我们就自己写一个类就好了 -->
<bean id="advice" class="cn.hncu2.v1.AroundAdvice"/>
<!-- 7.声明切面 : Advisor = pointcut + advice-->
<bean id="advisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
<property name="pointcut" ref="pointcut"/>
<property name="advice" ref="advice"></property>
</bean>
</beans>
前面 的匿名内部类
package cn.hncu2.v1;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
/**
* @author<a href="mailto:953801304@qq.com">胡龙华</a>
*/
public class AroundAdvice implements MethodInterceptor{
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("前面兰兰---XML");
Object obj = invocation.proceed();
System.out.println("后面兰兰---XML");
return obj;
}
}
测试:成功
——-未完待续,接着写—–
上面的MVC是第一个版本姑且称为v1_1.xml,其实我们可以简化,
下面是v1_2.xml:仅仅是把写在外部的bean 改到内部了
<bean id="factory" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" >
<bean id="p" class="cn.hncu2.v1.Person"/>
</property>
<property name="interceptorNames">
<list> <value>advisor</value> </list>
</property>
</bean>
<bean id="advisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
<property name="pointcut" >
<bean id="pointcut" class="org.springframework.aop.support.JdkRegexpMethodPointcut">
<property name="pattern" value=".*run.*"/>
</bean>
</property>
<property name="advice">
<bean id="advice" class="cn.hncu2.v1.AroundAdvice"/>
</property>
</bean>
接下来是v1_3.xml:与2的区别在于,把切点改为直接用正则表达式
<bean id="factory" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" >
<bean id="p" class="cn.hncu2.v1.Person"/>
</property>
<property name="interceptorNames">
<list> <value>advisor</value> </list>
</property>
</bean>
<!-- 与v1_2的区别在于 RegexpMethodPointcutAdvisor -->
<bean id="advisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<property name="patterns">
<array>
<value>.*run.*</value>
</array>
</property>
<property name="advice">
<bean id="advice" class="cn.hncu2.v1.AroundAdvice"/>
</property>
</bean>
接下来是v1_4.xml和v1_5:与前面的区别在于,没有采用前面三个版本的ProxyFactoryBean,改为自动代理,拿到时候直接拿Person
<!-- 自动代理 与前面三个版本的区别ProxyFactoryBean改为DefaultAdvisorAutoProxyCreator -->
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>
<bean id="advisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<property name="patterns">
<array>
<value>.*run.*</value>
</array>
</property>
<property name="advice">
<bean id="advice" class="cn.hncu2.v1.AroundAdvice"/>
</property>
</bean>
<!-- 把 ProxyFactoryBean 内部的bean拿出来-->
<bean id="p" class="cn.hncu2.v1.Person"/>
<bean id="cat" class="cn.hncu2.v1.Cat"/>
Spring写的自动代理有个缺点是 所以的都代理了,我有时候只想代理Person 而不想代理Cat… 怎么办? 手动写自动代理
MyAdvisorAutoProxyCreator.java
package cn.hncu2.v1;
import org.springframework.aop.Advisor;
import org.springframework.aop.framework.ProxyFactoryBean;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
public class MyAdvisorAutoProxyCreator implements ApplicationContextAware,BeanPostProcessor{
private ApplicationContext ctx;
@Override// 监听容器,一旦容器创建就拿到容器
public void setApplicationContext(ApplicationContext ctx)
throws BeansException {
this.ctx = ctx;
}
// 监听是否容器中的Bean是否被人拿出去
@Override//bean初始化后
public Object postProcessAfterInitialization(Object obj, String arg1)
throws BeansException {
if(obj instanceof Person){ // 只代理Person
ProxyFactoryBean factory = new ProxyFactoryBean();
factory.setTarget(obj);
Advisor advisor = ctx.getBean(Advisor.class);
factory.addAdvisors(advisor);
return factory.getObject();
}
return obj;
}
@Override// bean 初始化前
public Object postProcessBeforeInitialization(Object obj, String arg1)
throws BeansException {
return obj;
}
}
v1_5.xml
<!-- 我们写的自动代理 -->
<bean class="cn.hncu2.v1.MyAdvisorAutoProxyCreator"/>
<bean id="advisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<property name="patterns">
<array>
<value>.*run.*</value>
</array>
</property>
<property name="advice">
<bean id="advice" class="cn.hncu2.v1.AroundAdvice"/>
</property>
</bean>
<bean id="p" class="cn.hncu2.v1.Person"/>
<bean id="cat" class="cn.hncu2.v1.Cat"/>
上面就全面总结了SpringAop四种技术的第一种,明天开始我开始记录第二种,哈哈哈,一起进步学习吧!!!