Spring之AOP框架
本文内容纲要:Spring之AOP框架
AOP称为面向切面编程,其原理来自于代理模式,通过动态代理实现给程序增加新的功能。AOP是一种编程模式,它从另一种角度来思考程序结构并对面向对象编程进行补充。
AOP主要优点是:1)降低模块间的耦合度、2)使系统变得容易扩展、3)更好的代码复用。
AOP的实现技术分为两大类:一是静态织入,引入特定语法在编译期间织入方面代码,如AspectJ,二是动态代理技术,利用拦截消息的方式,在消息进行装饰以取代原有对象的行为。
Spring提供了基于动态AOP机制实现的AOP支持(即第二种方式),通过动态Proxy模式,在目标对象的方法调用前后插入相应的处理代码。
代理模式一般有三个角色:接口、代理和真实对象。其中代理与真实对象实现了同一接口,真实对象作用代理的一个属性,对外发布代理对象。当使用者调用代理的方法时,代理将转而调用真象的方法,在调用前后提供相关服务。
动态代理机制有两种方式:一是JAVA动态代理,特点是只能代理接口,采用JAVA的java.lang.reflection.Proxy来处理。二是CGLIB 代理,可代理接口和类(final method除外),采用CGLIB包来处理。
Java动态代理类位于Java.lang.reflect包下,一般主要涉及到以下两个类:
(1). Interface InvocationHandler
(2).Proxy:该类即为动态代理类
动态代理和普通的代理模式的区别,就是动态代理中的代理类是由java.lang.reflect.Proxy类在运行期时根据接口定义,采用Java反射功能动态生成的。例:
public interface Target {
public void say();
}
public class TargetImpl implements Target {
public TargetImpl () { }
public void say() {
System.out.println("Hello World.");
}
}
import java.lang.reflect.Method;
import java.lang.reflect.InvocationHandler;
public class TargetProxy implements InvocationHandler {
private Target sub;
public TargetProxy() {
}
public TargetProxy(Target obj) {
sub = obj;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("前置代理" + method);
method.invoke(sub, args);
System.out.println("后置代理" + method);
return null;
}
public static void main(String[] args) throws Throwable {
Target targetImpl = new TargetImpl(); //在这里指定被代理类
InvocationHandler ds = new TargetProxy(targetImpl); //初始化代理类
Class cls = targetImpl.getClass();
Target target = (Target) Proxy.newProxyInstance(cls.getClassLoader(), cls.getInterfaces(), ds);
target.say();
// Class c = Proxy.getProxyClass(cls.getClassLoader(),cls.getInterfaces()) ;
// Constructor ct=c.getConstructor(new Class[]{InvocationHandler.class});
// Target target =( Target) ct.newInstance(new Object[]{ds});
// target.request();
}
}
关于cglib的一个简单示例如下:
public class Target1 {
public void say(){
System.out.println("hello world");
}
}
public class CglibProxy implements MethodInterceptor {
private Enhancer enhancer = new Enhancer();
public Object getProxy(Class clazz) {
//设置需要创建子类的类
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
//通过字节码技术动态创建子类实例
return enhancer.create();
}
//实现MethodInterceptor接口方法
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("前置代理" + method);
//通过代理类调用父类中的方法
Object result = proxy.invokeSuper(obj, args);
System.out.println("后置代理"+ method);
return result;
}
public static void main(String[] args) {
CglibProxy proxy = new CglibProxy();
//通过生成子类的方式创建代理类
Target1 proxyImp = (Target1) proxy.getProxy(Target1.class);
proxyImp.say();
}
}
以上是关于动态代理技术的两个简单示例,Spring AOP实现了以上两种方式的动态代理技术,参考代码如下:
1.实现接口的类进行AOP,参见org.springframework.aop.framework.JdkDynamicAopProxy,主要方法如下:
public Object getProxy(ClassLoader classLoader) {
if (logger.isDebugEnabled()) {
logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());
}
Class[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised);
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this); //生成Proxy对象,this对应InvocationHandler对象,
}
org.springframework.aop.framework.ReflectiveMethodInvocation的主要方法如下:
public Object proceed() throws Throwable {
// We start with an index of -1 and increment early.
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
// Evaluate dynamic method matcher here: static part will already have
// been evaluated and found to match.
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
}
else {
// Dynamic matching failed.
// Skip this interceptor and invoke the next in the chain.
return proceed();
}
}
else {
// It's an interceptor, so we just invoke it: The pointcut will have
// been evaluated statically before this object was constructed.
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
2.从基类派生出来的类进行AOP,参见org.springframework.aop.framework .Cglib2AopProxy
public Object getProxy(ClassLoader classLoader) {
if (logger.isDebugEnabled()) {
logger.debug("Creating CGLIB2 proxy: target source is " + this.advised.getTargetSource());
}
try {
Class rootClass = this.advised.getTargetClass();
Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy");
Class proxySuperClass = rootClass;
if (AopUtils.isCglibProxyClass(rootClass)) {
proxySuperClass = rootClass.getSuperclass();
Class[] additionalInterfaces = rootClass.getInterfaces();
for (Class additionalInterface : additionalInterfaces) {
this.advised.addInterface(additionalInterface);
}
}
// Validate the class, writing log messages as necessary.
validateClassIfNecessary(proxySuperClass);
// Configure CGLIB Enhancer...
Enhancer enhancer = createEnhancer();
if (classLoader != null) {
enhancer.setClassLoader(classLoader);
if (classLoader instanceof SmartClassLoader &&
((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
enhancer.setUseCache(false);
}
}
enhancer.setSuperclass(proxySuperClass);
enhancer.setStrategy(new UndeclaredThrowableStrategy(UndeclaredThrowableException.class));
enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
enhancer.setInterceptDuringConstruction(false);
Callback[] callbacks = getCallbacks(rootClass);
enhancer.setCallbacks(callbacks);
enhancer.setCallbackFilter(new ProxyCallbackFilter(
this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
Class[] types = new Class[callbacks.length];
for (int x = 0; x < types.length; x++) {
types[x] = callbacks[x].getClass();
}
enhancer.setCallbackTypes(types);
// Generate the proxy class and create a proxy instance.
Object proxy;
if (this.constructorArgs != null) {
proxy = enhancer.create(this.constructorArgTypes, this.constructorArgs);
}
else {
proxy = enhancer.create();
}
return proxy;
}
catch (CodeGenerationException ex) {
throw new AopConfigException("Could not generate CGLIB subclass of class [" +
this.advised.getTargetClass() + "]: " +
"Common causes of this problem include using a final class or a non-visible class",
ex);
}
catch (IllegalArgumentException ex) {
throw new AopConfigException("Could not generate CGLIB subclass of class [" +
this.advised.getTargetClass() + "]: " +
"Common causes of this problem include using a final class or a non-visible class",
ex);
}
catch (Exception ex) {
// TargetSource.getTarget() failed
throw new AopConfigException("Unexpected AOP exception", ex);
}
}
Spring AOP框架是Spring的一个重要组成部分,但是Spring IoC容器并不依赖于AOP,所以我们可以在应用中不采用AOP。
AOP中有几个比较重要的概念:
1、join point(连接点):程序运行过程中的某个阶段点,它定义在哪里加入你的逻辑功能,对于Spring AOP,Jointpoint指的就是Method。
2、point cut(切入点):一系列连接点的集合,它指明通知(Advice)将在何时被触发。本质上是一个捕获连接点的结构。
3、advice(通知):在某个连接点所采用的处理逻辑,是point cut的执行代码,是执行“方面”的具体逻辑。
4、aspect(方面):对象操作过程中的截面,实际就是Advice和Pointcut的组合。它类似于OOP中定义的一个类,但它代表的更多是对象间横向的关系。
5、introduce(引入):用来给一个类型声明额外的方法或属性,为对象引入附加的方法或属性,从而达到修改对象结构的目的。
6、织入(Weaving):把切面连接到其它的应用程序类型或者对象上,并创建一个被通知的对象。这些可以在编译时、类加载时或运行时完成。
7、目标对象(Target Object): 被一个或者多个切面所通知的对象。也被称做被通知(advised)对象。
8、AOP代理(AOP Proxy):AOP框架创建的对象,用来实现切面契约。
通过切入点匹配连接点的概念是AOP的关键。切入点使得通知可以独立对应到面向对象的层次结构中。
Spring AOP 通知类型
Spring中提供了以下几种Advice:
1、BeforeAdvice:前置通知需实现MethodBeforeAdvice。BeforeAdvice可以修改目标的参数,也可以通过抛出异常来阻止目标运行。
2、AfterreturningAdvice:实现AfterreturningAdvice,我们无法修改方法的返回值,但是可以通过抛出异常阻止方法运行。
3、AroundAdvice:Spring 通过实现MethodInterceptor(aopalliance)来实现包围通知,最大特点是可以修改返回值,当然它在方法前后都加入了自己的逻辑代码,因此功能异常强大。通过MethodInvocation.proceed()来调用目标方法(甚至可以不调用)。
4、ThrowsAdvice:通过实现若干afterThrowing()来实现。
5、IntroductionInterceptor:Spring 的默认实现为DelegatingIntroductionInterceptor
Spring AOP机制提供两类方式实现类代理。一种是单个代理,一种是自动代理。自动代理又提供XML和注解两种配置方式
单个代理通过ProxyFactoryBean来实现,该方法只能为单个类配置代理。
自动代理通过BeanNameAutoProxyCreator或者 DefaultAdvisorAutoProxyCreator实现,它会自动为所有的增强所匹配的bean创建相应的代理。
以上两种方法可以只选用其中的一个来简化配置。
Spring AOP****编程式框架
Spring AOP框架中的编程过程:
1.声明目标对象接口,
2.实现目录对象
3.实现增强/通知/
4.实现切入点
5.使用代理机制
代码示例如下:
//目标对象接口. public interface Target { public String play(int arg); } |
//目标对象实现. public class TargetImpl implements Target { public String play(int arg) { System.out.println("play method...."); return "[Target:]" + arg; } } |
//前置增强 public class MyBeforeAdvice implements MethodBeforeAdvice { public void before(Method method, Object[] args, Object target) throws Throwable { System.out.println(method.getName()); System.out.println("before method!"); } } //后置增强 public class MyAfterAdvice implements AfterReturningAdvice { public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable { System.out.println(returnValue + ":after method"); } } |
public class Main { public static void main(String[] args) { Target target = new TargetImpl(); //目标对象 Advice beforeAdvice = new MyBeforeAdvice(); //增强 Pointcut pointcut = new MyPointcut(); //切入点 DefaultPointcutAdvisor dda = new DefaultPointcutAdvisor(); //切面 dda.setAdvice(beforeAdvice); //加入增强 dda.setPointcut(pointcut); //加入切入点
//1. 基本编程方式 AdvisedSupport advisedSupport = new AdvisedSupport(); advisedSupport.addAdvisor(dda); //加入切面 advisedSupport.addAdvice(new MyAfterAdvice()); //加入增强 advisedSupport.addInterface(Target.class); advisedSupport.setTarget(target); //加入目标代码 AopProxy aopProxy = new DefaultAopProxyFactory().createAopProxy(advisedSupport); Target proxy = (Target)aopProxy.getProxy(); System.out.println(proxy.play(200));
//2. 提供便利的编程方式. ProxyFactory proxyFactory = new ProxyFactory(); proxyFactory.addAdvisor(dda); //加入切面 proxyFactory.addInterface(Target.class); proxyFactory.setTarget(target); //加入目标代码 Target proxy2 = (Target)proxyFactory.getProxy(); System.out.println(proxy2.play(201));
//3. 提供便利的编程方式.
ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean(); proxyFactoryBean.addAdvisor(dda); //加入切面 proxyFactoryBean.addInterface(Target.class); proxyFactoryBean.setTarget(target); //加入目标代码 Target proxy3 = (Target)proxyFactoryBean.getObject(); System.out.println(proxy3.play(232)); } } |
Spring AOP****配置总结
- XML配置方式
BeanNameAutoProxyCreator: BeanNameAutoProxyCreator将为名字匹配字符串或者通配符的bean自动创建AOP代理。通常接受两个参数。第一个是beanNames属性,该属性用来设置哪些bean需要自动生成代理。另一个属性是interceptorNames,该属性指定了事务拦截器,当自动创建事务代理时,系统会根据这些事务拦截器的属性来生成对应的事务代理。
<bean id=" WelcomeInterceptor " class=" AutoProxySample.WelcomeInterceptor "/> <bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"> <!-- 指定对满足哪些bean name的bean自动生成业务代理 --> <property name="beanNames"> <!-- 下面是所有需要创建自动代理的bean--> <list> <value> personABean </value> <value> personBBean </value> </list> <!-- 此处可增加其他需要创建自动代理的bean--> </property> <!-- 下面定义BeanNameAutoProxyCreator所需的拦截器--> <property name="interceptorNames"> <list> <value> WelcomeInterceptor </value> <!-- 此处可增加其他新的Interceptor --> </list> </property> </bean>
<!--由BeanNameAutoProxyCreator生成自动代理--> <bean id="personABean" class="AutoProxySample.PersonA"> </bean> <bean id="personBBean" class="AutoProxySample.PersonB"> <!-- 与PersonA实现相同接口的业务实现类 --> |
DefaultAdvisorAutoProxyCreator:DefaultAdvisorAutoProxyCreator这个类功能更为强大,实现了BeanProcessor接口,它将描述ApplicationCentext读取到的所有Bean的信息,寻找所有的Advistor,并将这些Advisor应用到所有符合切入点的Bean中。(一个Advisor是一个切入点和一个通知的组成)
<bean id="WelcomeAdvice" class="AutoProxySample.WelcomeAdvice"></bean>
<!-- 自动代理所有的advisor --> <bean id="autoProxyCreator" class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"> </bean>
<bean id="advisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"> <property name="pattern"> <value>.*say.+</value> <!-- 业务实现方法名匹配 --> </property> <property name="advice"> <ref bean="WelcomeAdvice"/> <!-- 实现前置通知接口的类--> </property> </bean>
<bean id="personABean" class="AutoProxySample.PersonA"> <!-- 业务实现类 --> </bean> <bean id="personBBean" class="AutoProxySample.PersonB"> <!-- 与PersonA实现相同接口的业务实现类 --> </bean> |
相关的Java代码如下:
package AutoProxySample;
public interface Person { public void say(); public void hear(); }
package AutoProxySample;
public class PersonA implements Person { public String say() { System.out.println(this.getName()+" said: Hello Word!"); return null; }
public String hear(String s) { System.out.println(this.getName()+" hear: "+s); return null; } }
package AutoProxySample;
public class PersonB implements Person { public String say() { System.out.println(this.getName()+" said: Hello Word!"); return null; } public String hear(String s) { System.out.println(this.getName()+" hear: "+s); return null; } }
package AutoProxySample;
import java.lang.reflect.Method;
import org.springframework.aop.MethodBeforeAdvice; //前置通知 public class WelcomeAdvice implements MethodBeforeAdvice { public void before(Method method, Object[] args, Object obj) throws Throwable { System.out.println("Hello welcome to bye "); } } |
2。注解方式配置
针对一个接口和接口的实现类,这里使用AutoProxySample.Person和AutoProxySample.PersonA两个类,使用Spring注解方式对PersonA进行方法拦截。
定义一个切面,对PersonA进行方法拦截,如下:
package AutoProxySample;
/** */ /** System.out.println("前置通知"); /** /** Object object = pjp.proceed();//执行该方法 System.out.println("退出方法"); return object; } /** public void doThrow(JoinPoint jp, Throwable e) { } |
|
然后在Spring的配置文件中配置该Bean,需要打开AOP命名空间
<aop:aspectj-autoproxy/> <bean id="personABean" class="AutoProxySample.PersonA"/> <bean id="myProxy" class="AutoProxySample.AspectAdvice"/> |
本文内容总结:Spring之AOP框架
原文链接:https://www.cnblogs.com/jevo/archive/2013/03/21/2966993.html
以上是 Spring之AOP框架 的全部内容, 来源链接: utcz.com/z/296665.html