Spring 学习十五 AOP

时间:2021-08-08 02:43:41

http://www.hongyanliren.com/2014m12/22797.html

1: 通知(advice):
就是你想要的功能,也就是安全、事物、日子等。先定义好,在想用的地方用一下。包含Aspect的一段代码
2: 连接点(joinPoint):
spring允许你通知的地方,很多,基本每个方法的前、后,或抛出异常时都可以是连接点。
spring 只支持方法连接点。 其它如AspectJ还可以让你在构造器或属性注入时都行。
3: 切入点(pointcut):
一个类,15个方法,就是15个连接点,但是你不想在所有的方法都用通知,只是让其中几个,在调用这个方法之前,之后
或者抛出异常的时候干点什么,那么就用切入点来定义这几个方法,让切入点选择连接点,选中那几个你想要的方法。
4: 切面(Aspect)
切面是通知advice和切入点的结合,连接点只是为了让理解切点搞出来的,通知说明了干什么和什么时候干(before,afer等
定义了通知干活的时间)切入点说明了在哪干(就是指明方法)
5: 引入(introduction)
允许我们向现有的类添加新方法属性。这不就是把切面(也就是新方法属性:通知定义的)用到目标类中吗。
可以无需修改现有的类的情况下,让他们有新的行为和状态。
6: 目标(target)
引入中所提到的目标类,也就是要被通知的对象,也就是真正的业务逻辑,他可以在毫不知情的情况下,被织入切面。自己
只是关注业务本身逻辑。
7:代理(proxy): 由AOP生成的java对象。
8: 织入(weaving):把切面应用到目标对象来创建新的代理对象的过程。有3种方式。
编译期: 切面在目标类编译期被织入,这种方式需要特殊的编译器,如AspectJ.
类加载期: 切面在目标类加载到JVM时被织入,这种方式要特殊的类加载器。
运行期: Spring AOP用的这种方式。
9: 横切关注点: log\安全检查等。

AOP原理:
spring 用代理类包裹切面,把他们织入到spring管理的bean中,也就是说代理类伪装成目标类,它会截取对目标类中方法
的调用,调用者对目标类对调用都先变成伪装类,伪装类先执行切面,再把调用转给真正目标bean。

如何搞出个伪装类,才不会被调用者发现,如下两种方法:
1) 实现和目标类相同的接口:
我也实现和你一样的接口,反正上层都是接口级别的调用,逃过了类型检查,到java运行期的时候,利用多态的后期绑定(所以spring
采用运行时),伪装类(代理类)就变成了接口的真正实现,他里面包裹了真实的目标类,最后实现具体功能的还是目标类,伪装类干了点
额外的事情(写日志、安全检查、事物等)。

这种模式,spring用JDK的java.lang.reflect.Proxy类,它允许Spring动态生成一个新类来实现必要的接口,织入通知,并且把
这些接口的任何调用都转发到目标类。

2) 生成子类调用
用子类做伪装,逃过类型检查,重写的方法实现了目标类的功能,还在这些功能之前,实现了一些其它的(写日志,安全检查,事物)

spring使用CGLIB库生成目标类的一个子类,在创建这个子类的时候,spring织入通知。

前一种模式更好,松耦合,尤其在今天高喊着面向接口编程的情况下。

面向切面编程,在我们的应用中,经常需要做一些事情,但是这些事情与核心业务无关,比如,要记录所有update*方法的执行时间时间,操作人等等信息,记录到日志,

通过spring的AOP技术,就可以在不修改update*的代码的情况下完成该需求。

AOP实现原理-----代理

////////////////////////////////////////////////////////////////////////////////////
1: Spring通知几种类型?
org.aopalliance.intercept.MethodInterceptor
org.springframework.aop.MethodBeforeAdvice
org.springframework.aop.AfterReturningAdvice
org.springframework.aop.ThrowsAdvice
2. 谈谈目标对象实现接口与目标对象不实现接口有什么区别?
其中动态代理又可分为:
1.JDK动态代理
此时代理对象和目标对象实现了相同的接口,目标对象作为代理对象的一个属性,具体接口实现中,可以在调用目标对象相应方法前后加上其他业务处理逻辑。
代理模式在实际使用时需要指定具体的目标对象,如果为每个类都添加一个代理类的话,会导致类很多,同时如果不知道具体类的话,怎样实现代理模式呢?这就引出动态代理。
JDK动态代理只能针对实现了接口的类生成代理。
2.CGLIB代理
CGLIB(CODE GENERLIZE LIBRARY)代理是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的所有方法,所以该类或方法不能声明称final的。

3. 请描述JDK动态代理和CGLI代理的区别?
4:简述ProxyFactoryBean的作用是什么?
使用Spring提供的类org.springframework.aop.framework.ProxyFactoryBean是创建AOP的最基本的方式 .

第一种方式: 使用ProxyFactoryBean代理目标类的所有方法
<bean id="logProxy" class="org.springframework.aop.framework.ProxyFactoryBean">

<!--这里代理的是接口-->
<property name="proxyInterfaces">
<value>com.gc.impl.TimeBookInterface</value>
</property>

<!--是ProxyFactoryBean要代理的目标类-->
<property name="target">
<ref bean="timeBook"/>
</property>

<!--程序中的Advice-->
<property name="interceptorNames">
<list>
<value>log</value> // 这里的log可以是5中通知中的一种。
</list>
</property>
</bean>
</beans>

第二种方式: 使用ProxyFactoryBean代理目标类的指定方法:
<bean id="logAdvisor"class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<property name="advice">
<ref bean="log"/>
</property>

<!--指定要代理的方法-->
<property name="patterns">
<value>.*doAuditing.* </value>
</property>
</bean>

<!--设定代理类-->
<bean id="logProxy" class="org.springframework.aop.framework.ProxyFactoryBean">

<property name="proxyInterfaces">
<value>com.gc.impl.TimeBookInterface</value>
</property>

<property name="target">
<ref bean="timeBook"/>
</property>

<property name="interceptorNames">
<list>
<value>logAdvisor</value>
</list>
</property>
</bean>
</beans>

5. 写出创建代理对象需指定的三要素是什么?

实现的接口/被代理的对象是谁/ 5种通知中的哪个或哪几个
6:写出代理的两种方式分别是什么?
java用的是动态代理实现的AOP,而非静态代理。
静态代理的方式:是编译器就确定好了的。

动态代理两种实现方法:
1: 基于java JDK 的动态代理。
public class DynamicProxy implements InvocationHandler {

private Object target; // 被代理的对象
public Object bind(Object target) { // 把这个代理和目标绑定,需要proxy也实现和目标一样的接口
this.target = target;
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("切面之前执行");
// 执行业务
method.invoke(target, args);
System.out.println("切面之后执行");
return null;
}

DynamicProxy proxy = new DynamicProxy();
BookFacade bookProxy = (BookFacade) proxy.bind(new BookFacadeImpl());
bookProxy.addBook();
2:
public class BookFacadeCglib implements MethodInterceptor {
private Object target;

/**
* 创建代理对象
*
* @param target
* @return
*/
public Object getInstance(Object target) {
this.target = target;
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(this.target.getClass());
// 回调方法
enhancer.setCallback(this);
// 创建代理对象
return enhancer.create();
}

@Override
// 回调方法
public Object intercept(Object obj, Method method, Object[] args,
MethodProxy proxy) throws Throwable {
System.out.println("事物开始");
proxy.invokeSuper(obj, args);
System.out.println("事物结束");
return null;

}

Spring中AOP的两种动态的两种方式
1.是用java反射机制,只能对实现了接口的类生成代理,而不能针对类
2.cgLib 可以不用接口,它底层调用asm 动态生成一个代理类去覆盖父类中非 final 的方法,然后实现 MethodInterceptor 接口的 intercept 方法,这样以后直接调用重写的方法,比 JDK 要快。但是加载 cglib 消耗时间比直接 JDK 反射时间长,开发的过程中,如果是反复动态生成新的代理类推荐用 JDK 自身的反射,反之用 cglib。

1、如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP
2、如果目标对象实现了接口,可以强制使用CGLIB实现AOP
3、如果目标对象没有实现了接口,必须采用CGLIB库,spring会自动在JDK动态代理和CGLIB之间转换

JDK动态代理和CGLIB字节码生成的区别?
* JDK动态代理只能对实现了接口的类生成代理,而不能针对类
* CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法
因为是继承,所以该类或方法最好不要声明成final

7: AOP事务的含义:

切面:
1: 通知(advice):
就是你想要的功能,也就是安全、事物、日志等。先定义好,在想用的地方用一下。包含Aspect的一段代码
2: 连接点(joinPoint):
spring允许你通知的地方,很多,基本每个方法的前、后,或抛出异常时都可以是连接点。
spring 只支持方法连接点。 其它如AspectJ还可以让你在构造器或属性注入时都行。
3: 切入点(pointcut):
一个类,15个方法,就是15个连接点,但是你不想在所有的方法都用通知,只是让其中几个,在调用这个方法之前,之后
或者抛出异常的时候干点什么,那么就用切入点来定义这几个方法,让切入点选择连接点,选中那几个你想要的方法。
4: 切面(Aspect)
切面是通知和切入点的结合,连接点只是为了让理解切点搞出来的,通知说明了干什么和什么时候干(before,afer等
定义了通知干活的时间)切入点说明了在哪干(就是指明方法)
5: 引入(introduction)
允许我们向现有的类添加新方法属性。这不就是把切面(也就是新方法属性:通知定义的)用到目标类中吗。
可以无需修改现有的类的情况下,让他们有新的行为和状态。
6: 目标(target)
引入中所提到的目标类,也就是要被通知的对象,也就是真正的业务逻辑,他可以在毫不知情的情况下,被织入切面。自己
只是关注业务本身逻辑。
7:代理(proxy): 由AOP生成的java对象。
8: 织入(weaving):把切面应用到目标对象来创建新的代理对象的过程。有3种方式。
编译期: 切面在目标类编译期被织入,这种方式需要特殊的编译器,如AspectJ.
类加载期: 切面在目标类加载到JVM时被织入,这种方式要特殊的类加载器。
运行期: Spring AOP用的这种方式。
9: 横切关注点: log\安全检查等。
AOP原理: 在不需要改变现有代码的前提下,增加功能。
spring 用代理类包裹切面,把他们织入到spring管理的bean中,也就是说代理类伪装成目标类,它会截取对目标类中方法
的调用,调用者对目标类对调用都先变成伪装类,伪装类先执行切面,再把调用转给真正目标bean。
如何搞出个伪装类,才不会被调用者发现,如下两种方法:
1) 实现和目标类相同的接口:
我也实现和你一样的接口,反正上层都是接口级别的调用,逃过了类型检查,到java运行期的时候,利用多态的后期绑定(所以spring
采用运行时),伪装类(代理类)就变成了接口的真正实现,他里面包裹了真实的目标类,最后实现具体功能的还是目标类,伪装类干了点
额外的事情(写日志、安全检查、事物等)。
这种模式,spring用JDK的java.lang.reflect.Proxy类,它允许Spring动态生成一个新类来实现必要的接口,织入通知,并且把
这些接口的任何调用都转发到目标类。
2) 生成子类调用
用子类做伪装,逃过类型检查,重写的方法实现了目标类的功能,还在这些功能之前,实现了一些其它的(写日志,安全检查,事物)
spring使用CGLIB库生成目标类的一个子类,在创建这个子类的时候,spring织入通知。
前一种模式更好,松耦合,尤其在今天高喊着面向接口编程的情况下。
它可以通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术.如果您学习Java的话,会在Spring中经常用到,那是你更能领悟它
主要的功能是:日志记录,性能统计,安全控制,事务处理,异常处理,Caching 缓存
等等。 从业务逻辑代码中划分出来,通过对这些行为的分离,我们希望可以将它们独立到非指导业务逻辑的方法中,进而改变这些行为的时候不影响业务逻辑的代码。

http://www.hongyanliren.com/2014m12/22797.html

1: 通知(advice):
就是你想要的功能,也就是安全、事物、日子等。先定义好,在想用的地方用一下。包含Aspect的一段代码
2: 连接点(joinPoint):
spring允许你通知的地方,很多,基本每个方法的前、后,或抛出异常时都可以是连接点。
spring 只支持方法连接点。 其它如AspectJ还可以让你在构造器或属性注入时都行。
3: 切入点(pointcut):
一个类,15个方法,就是15个连接点,但是你不想在所有的方法都用通知,只是让其中几个,在调用这个方法之前,之后
或者抛出异常的时候干点什么,那么就用切入点来定义这几个方法,让切入点选择连接点,选中那几个你想要的方法。
4: 切面(Aspect)
切面是通知advice和切入点的结合,连接点只是为了让理解切点搞出来的,通知说明了干什么和什么时候干(before,afer等
定义了通知干活的时间)切入点说明了在哪干(就是指明方法)
5: 引入(introduction)
允许我们向现有的类添加新方法属性。这不就是把切面(也就是新方法属性:通知定义的)用到目标类中吗。
可以无需修改现有的类的情况下,让他们有新的行为和状态。
6: 目标(target)
引入中所提到的目标类,也就是要被通知的对象,也就是真正的业务逻辑,他可以在毫不知情的情况下,被织入切面。自己
只是关注业务本身逻辑。
7:代理(proxy): 由AOP生成的java对象。
8: 织入(weaving):把切面应用到目标对象来创建新的代理对象的过程。有3种方式。
编译期: 切面在目标类编译期被织入,这种方式需要特殊的编译器,如AspectJ.
类加载期: 切面在目标类加载到JVM时被织入,这种方式要特殊的类加载器。
运行期: Spring AOP用的这种方式。
9: 横切关注点: log\安全检查等。

AOP原理:
spring 用代理类包裹切面,把他们织入到spring管理的bean中,也就是说代理类伪装成目标类,它会截取对目标类中方法
的调用,调用者对目标类对调用都先变成伪装类,伪装类先执行切面,再把调用转给真正目标bean。

如何搞出个伪装类,才不会被调用者发现,如下两种方法:
1) 实现和目标类相同的接口:
我也实现和你一样的接口,反正上层都是接口级别的调用,逃过了类型检查,到java运行期的时候,利用多态的后期绑定(所以spring
采用运行时),伪装类(代理类)就变成了接口的真正实现,他里面包裹了真实的目标类,最后实现具体功能的还是目标类,伪装类干了点
额外的事情(写日志、安全检查、事物等)。

这种模式,spring用JDK的java.lang.reflect.Proxy类,它允许Spring动态生成一个新类来实现必要的接口,织入通知,并且把
这些接口的任何调用都转发到目标类。

2) 生成子类调用
用子类做伪装,逃过类型检查,重写的方法实现了目标类的功能,还在这些功能之前,实现了一些其它的(写日志,安全检查,事物)

spring使用CGLIB库生成目标类的一个子类,在创建这个子类的时候,spring织入通知。

前一种模式更好,松耦合,尤其在今天高喊着面向接口编程的情况下。

面向切面编程,在我们的应用中,经常需要做一些事情,但是这些事情与核心业务无关,比如,要记录所有update*方法的执行时间时间,操作人等等信息,记录到日志,

通过spring的AOP技术,就可以在不修改update*的代码的情况下完成该需求。

AOP实现原理-----代理

////////////////////////////////////////////////////////////////////////////////////
1: Spring通知几种类型?
org.aopalliance.intercept.MethodInterceptor
org.springframework.aop.MethodBeforeAdvice
org.springframework.aop.AfterReturningAdvice
org.springframework.aop.ThrowsAdvice
2. 谈谈目标对象实现接口与目标对象不实现接口有什么区别?
其中动态代理又可分为:
1.JDK动态代理
此时代理对象和目标对象实现了相同的接口,目标对象作为代理对象的一个属性,具体接口实现中,可以在调用目标对象相应方法前后加上其他业务处理逻辑。
代理模式在实际使用时需要指定具体的目标对象,如果为每个类都添加一个代理类的话,会导致类很多,同时如果不知道具体类的话,怎样实现代理模式呢?这就引出动态代理。
JDK动态代理只能针对实现了接口的类生成代理。
2.CGLIB代理
CGLIB(CODE GENERLIZE LIBRARY)代理是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的所有方法,所以该类或方法不能声明称final的。

3. 请描述JDK动态代理和CGLI代理的区别?
4:简述ProxyFactoryBean的作用是什么?
使用Spring提供的类org.springframework.aop.framework.ProxyFactoryBean是创建AOP的最基本的方式 .

第一种方式: 使用ProxyFactoryBean代理目标类的所有方法
<bean id="logProxy" class="org.springframework.aop.framework.ProxyFactoryBean">

<!--这里代理的是接口-->
<property name="proxyInterfaces">
<value>com.gc.impl.TimeBookInterface</value>
</property>

<!--是ProxyFactoryBean要代理的目标类-->
<property name="target">
<ref bean="timeBook"/>
</property>

<!--程序中的Advice-->
<property name="interceptorNames">
<list>
<value>log</value> // 这里的log可以是5中通知中的一种。
</list>
</property>
</bean>
</beans>

第二种方式: 使用ProxyFactoryBean代理目标类的指定方法:
<bean id="logAdvisor"class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<property name="advice">
<ref bean="log"/>
</property>

<!--指定要代理的方法-->
<property name="patterns">
<value>.*doAuditing.* </value>
</property>
</bean>

<!--设定代理类-->
<bean id="logProxy" class="org.springframework.aop.framework.ProxyFactoryBean">

<property name="proxyInterfaces">
<value>com.gc.impl.TimeBookInterface</value>
</property>

<property name="target">
<ref bean="timeBook"/>
</property>

<property name="interceptorNames">
<list>
<value>logAdvisor</value>
</list>
</property>
</bean>
</beans>

5. 写出创建代理对象需指定的三要素是什么?

实现的接口/被代理的对象是谁/ 5种通知中的哪个或哪几个
6:写出代理的两种方式分别是什么?
java用的是动态代理实现的AOP,而非静态代理。
静态代理的方式:是编译器就确定好了的。

动态代理两种实现方法:
1: 基于java JDK 的动态代理。
public class DynamicProxy implements InvocationHandler {

private Object target; // 被代理的对象
public Object bind(Object target) { // 把这个代理和目标绑定,需要proxy也实现和目标一样的接口
this.target = target;
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("切面之前执行");
// 执行业务
method.invoke(target, args);
System.out.println("切面之后执行");
return null;
}

DynamicProxy proxy = new DynamicProxy();
BookFacade bookProxy = (BookFacade) proxy.bind(new BookFacadeImpl());
bookProxy.addBook();
2:
public class BookFacadeCglib implements MethodInterceptor {
private Object target;

/**
* 创建代理对象
*
* @param target
* @return
*/
public Object getInstance(Object target) {
this.target = target;
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(this.target.getClass());
// 回调方法
enhancer.setCallback(this);
// 创建代理对象
return enhancer.create();
}

@Override
// 回调方法
public Object intercept(Object obj, Method method, Object[] args,
MethodProxy proxy) throws Throwable {
System.out.println("事物开始");
proxy.invokeSuper(obj, args);
System.out.println("事物结束");
return null;

}

Spring中AOP的两种动态的两种方式
1.是用java反射机制,只能对实现了接口的类生成代理,而不能针对类
2.cgLib 可以不用接口,它底层调用asm 动态生成一个代理类去覆盖父类中非 final 的方法,然后实现 MethodInterceptor 接口的 intercept 方法,这样以后直接调用重写的方法,比 JDK 要快。但是加载 cglib 消耗时间比直接 JDK 反射时间长,开发的过程中,如果是反复动态生成新的代理类推荐用 JDK 自身的反射,反之用 cglib。

1、如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP
2、如果目标对象实现了接口,可以强制使用CGLIB实现AOP
3、如果目标对象没有实现了接口,必须采用CGLIB库,spring会自动在JDK动态代理和CGLIB之间转换

JDK动态代理和CGLIB字节码生成的区别?
* JDK动态代理只能对实现了接口的类生成代理,而不能针对类
* CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法
因为是继承,所以该类或方法最好不要声明成final

7: AOP事务的含义:

切面:
1: 通知(advice):
就是你想要的功能,也就是安全、事物、日志等。先定义好,在想用的地方用一下。包含Aspect的一段代码
2: 连接点(joinPoint):
spring允许你通知的地方,很多,基本每个方法的前、后,或抛出异常时都可以是连接点。
spring 只支持方法连接点。 其它如AspectJ还可以让你在构造器或属性注入时都行。
3: 切入点(pointcut):
一个类,15个方法,就是15个连接点,但是你不想在所有的方法都用通知,只是让其中几个,在调用这个方法之前,之后
或者抛出异常的时候干点什么,那么就用切入点来定义这几个方法,让切入点选择连接点,选中那几个你想要的方法。
4: 切面(Aspect)
切面是通知和切入点的结合,连接点只是为了让理解切点搞出来的,通知说明了干什么和什么时候干(before,afer等
定义了通知干活的时间)切入点说明了在哪干(就是指明方法)
5: 引入(introduction)
允许我们向现有的类添加新方法属性。这不就是把切面(也就是新方法属性:通知定义的)用到目标类中吗。
可以无需修改现有的类的情况下,让他们有新的行为和状态。
6: 目标(target)
引入中所提到的目标类,也就是要被通知的对象,也就是真正的业务逻辑,他可以在毫不知情的情况下,被织入切面。自己
只是关注业务本身逻辑。
7:代理(proxy): 由AOP生成的java对象。
8: 织入(weaving):把切面应用到目标对象来创建新的代理对象的过程。有3种方式。
编译期: 切面在目标类编译期被织入,这种方式需要特殊的编译器,如AspectJ.
类加载期: 切面在目标类加载到JVM时被织入,这种方式要特殊的类加载器。
运行期: Spring AOP用的这种方式。
9: 横切关注点: log\安全检查等。
AOP原理: 在不需要改变现有代码的前提下,增加功能。
spring 用代理类包裹切面,把他们织入到spring管理的bean中,也就是说代理类伪装成目标类,它会截取对目标类中方法
的调用,调用者对目标类对调用都先变成伪装类,伪装类先执行切面,再把调用转给真正目标bean。
如何搞出个伪装类,才不会被调用者发现,如下两种方法:
1) 实现和目标类相同的接口:
我也实现和你一样的接口,反正上层都是接口级别的调用,逃过了类型检查,到java运行期的时候,利用多态的后期绑定(所以spring
采用运行时),伪装类(代理类)就变成了接口的真正实现,他里面包裹了真实的目标类,最后实现具体功能的还是目标类,伪装类干了点
额外的事情(写日志、安全检查、事物等)。
这种模式,spring用JDK的java.lang.reflect.Proxy类,它允许Spring动态生成一个新类来实现必要的接口,织入通知,并且把
这些接口的任何调用都转发到目标类。
2) 生成子类调用
用子类做伪装,逃过类型检查,重写的方法实现了目标类的功能,还在这些功能之前,实现了一些其它的(写日志,安全检查,事物)
spring使用CGLIB库生成目标类的一个子类,在创建这个子类的时候,spring织入通知。
前一种模式更好,松耦合,尤其在今天高喊着面向接口编程的情况下。
它可以通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术.如果您学习Java的话,会在Spring中经常用到,那是你更能领悟它
主要的功能是:日志记录,性能统计,安全控制,事务处理,异常处理,Caching 缓存
等等。 从业务逻辑代码中划分出来,通过对这些行为的分离,我们希望可以将它们独立到非指导业务逻辑的方法中,进而改变这些行为的时候不影响业务逻辑的代码。