图片 spa 应用 framework round 子类 cee 过程 访问
什么是 AOP
Spring 是解决实际开发中的一些问题:
* AOP 解决 OOP 中遇到的一些问题. 是 OOP 的延续和扩展.
AOP 作用
对程序进行增强: 不修改源码的情况下.
* AOP 可以进行权限校验, 日志记录, 性能监控, 事务控制.
Spring 的 AOP 的由来:
AOP 最早由 AOP 联盟的组织提出的, 制定了一套规范. Spring 将 AOP 思想引入到框架中, 必须遵守 AOP 联盟的规范.
底层实现:
代理机制:
* Spring 的 AOP 的底层用到两种代理机制:
* JDK 的动态代理: 针对实现了接口的类产生代理.
* Cglib 的动态代理 : 针对没有实现接口的类产生代理. 应用的是底层的字节码增强的技术 生成当前类的子类对象.
动态代理
1 运行时实现指定的接口
想实现某个接口,你需要写一个类,然后在类名字的后面给出 "implements"XXX 接口.这才是实现某个接口:
上面的代码对我们来说没有什么新鲜感,我们要说的是动态代理技术可以通过一个方法调用就可以生成一个对指定接口的实现类对象.
publicinterfaceMyInterface{
void fun1();
void fun2();
}
publicclassMyInterfaceImplimplementsMyInterface{
publicvoid fun1(){
System.out.println("fun1()");
}
publicvoid fun2(){
System.out.println("fun2()");
}
}
上面代码中,Proxy 类的静态方法 newProxyInstance() 方法生成了一个对象,这个对象实现了 cs 数组中指定的接口.没错,返回值 mi 是 MyInterface 接口的实现类.你不要问这个类是哪个类,你只需要知道 mi 是 MyInterface 接口的实现类就可以了.你现在也不用去管 loader 和 h 这两个参数是什么东东,你只需要知道,Proxy 类的静态方法 newProxyInstance() 方法返回的方法是实现了指定接口的实现类对象,甚至你都没有看见实现类的代码.
Class[] cs = {MyInterface.class};
MyInterface mi = (MyInterface)Proxy.newProxyInstance(loader, cs, h);
动态代理就是在运行时生成一个类,这个类会实现你指定的一组接口,而这个类没有. java 文件,是在运行时生成的,你也不用去关心它是什么类型的,你只需要知道它实现了哪些接口即可.
2newProxyInstance() 方法的参数
Proxy 类的 newInstance() 方法有三个参数:
l ClassLoader loader:它是类加载器类型,你不用去理睬它,你只需要知道怎么可以获得它就可以了:MyInterface.class.getClassLoader() 就可以获取到 ClassLoader 对象,没错,只要你有一个 Class 对象就可以获取到 ClassLoader 对象;
l Class[] interfaces:指定 newProxyInstance() 方法返回的对象要实现哪些接口,没错,可以指定多个接口,例如上面例子只我们只指定了一个接口:Class[] cs = {MyInterface.class};
l InvocationHandler h:它是最重要的一个参数!它是一个接口!它的名字叫调用处理器!你想一想,上面例子中 mi 对象是 MyInterface 接口的实现类对象,那么它一定是可以调用 fun1() 和 fun2() 方法了,难道你不想调用一下 fun1() 和 fun2() 方法么,它会执行些什么东东呢?其实无论你调用代理对象的什么方法,它都是在调用 InvocationHandler 的 invoke() 方法!
InvocationHandler 接口只有一个方法,即 invoke() 方法!它是对代理对象所有方法的唯一实现.也就是说,无论你调用代理对象上的哪个方法,其实都是在调用 InvocationHandler 的 invoke() 方法.
publicstaticvoid main(String[] args){
Class[] cs ={MyInterface.class};
ClassLoader loader =MyInterface.class.getClassLoader();
InvocationHandler h =newInvocationHandler(){
publicObject invoke(Object proxy,Method method,Object[] args)
throwsThrowable{
System.out.println("无论你调用代理对象的什么方法,其实都是在调用invoke()...");
returnnull;
}
};
MyInterface mi =(MyInterface)Proxy.newProxyInstance(loader, cs, h);
mi.fun1();
mi.fun2();
}
想象中的类:
注意,X 类是我们用来理解代理对象与 InvocationHandler 之间的关系的,但它是不存在的类.是我们想象出来的!也就是说,它是用来说明,无论你调用代理对象的哪个方法,最终调用的都是调用处理器的 invoke() 方法.
class X implementsMyInterface{
privateInvocationHandler h;
public X(InvocationHandler h){
this.h = h;
}
publicvoid fun1(){
h.invoke();
}
publicvoid fun2(){
h.invoke();
}
}
3InvocationHandler 的 invoke() 方法
InvocationHandler 的 invoke() 方法的参数有三个:
l Object proxy:代理对象,也就是 Proxy.newProxyInstance() 方法返回的对象,通常我们用不上它;
l Method method:表示当前被调用方法的反射对象,例如 mi.fun1(),那么 method 就是 fun1() 方法的反射对象;
l Object[] args:表示当前被调用方法的参数,当然 mi.fun1() 这个调用是没有参数的,所以 args 是一个零长数组.
最后要说的是 invoke() 方法的返回值为 Object 类型,它表示当前被调用的方法的返回值,当然 mi.fun1() 方法是没有返回值的,所以 invoke() 返回的就必须是 null 了.
AOP 的开发中的相关术语:
publicstaticvoid main(String[] args){
Class[] cs ={MyInterface.class};
ClassLoader loader =MyInterface.class.getClassLoader();
InvocationHandler h =newInvocationHandler(){
publicObject invoke(Object proxy,Method method,Object[] args)
throwsThrowable{
System.out.println("当前调用的方法是:"+ method.getName());
returnnull;
}
};
MyInterface mi =(MyInterface)Proxy.newProxyInstance(loader, cs, h);
mi.fun1();
mi.fun2();
}
Joinpoint(连接点): 所谓连接点是指那些被拦截到的点.在 spring 中, 这些点指的是方法, 因为 spring 只支持方法类型的连接点.
Pointcut(切入点): 所谓切入点是指我们要对哪些 Joinpoint 进行拦截的定义.
Advice(通知 / 增强): 所谓通知是指拦截到 Joinpoint 之后所要做的事情就是通知. 通知分为前置通知, 后置通知, 异常通知, 最终通知, 环绕通知 (切面要完成的功能)
Introduction(引介): 引介是一种特殊的通知在不修改类代码的前提下, Introduction 可以在运行期为类动态地添加一些方法或 Field.
Target(目标对象): 代理的目标对象
Weaving(织入): 是指把增强应用到目标对象来创建新的代理对象的过程.
spring 采用动态代理织入,而 AspectJ 采用编译期织入和类装在期织入
Proxy(代理): 一个类被 AOP 织入增强后,就产生一个结果代理类
Aspect(切面): 是切入点和通知(引介)的结合
Spring 使用 AspectJ 进行 AOP 的开发:XML 的方式(*****)
引入相应的 jar 包
* spring 的传统 AOP 的开发的包
* aspectJ 的开发包:
spring-aop-4.2.4.RELEASE.jar
com.springsource.org.aopalliance-1.0.0.jar
com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
spring-aspects-4.2.4.RELEASE.jar
引入 Spring 的配置文件
引入 AOP 约束:
通知类型
<beansxmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
</beans>
前置通知 :在目标方法执行之前执行
后置通知 :在目标方法执行之后执行
环绕通知 :在目标方法执行前和执行后执行
异常抛出通知:在目标方法执行出现 异常的时候执行
最终通知 :无论目标方法是否出现异常最终通知都会执行
切入点表达式
execution(表达式)
表达式:
[方法访问修饰符] 方法返回值 包名. 类名. 方法名 (方法的参数)
案例
public * cn.spring.dao.*.*(..)
* cn.spring.dao.*.*(..)
* cn.spring.dao.UserDao+.*(..)
* cn.spring.dao..*.*(..)
其他的增强的配置:
Spring 使用 AspectJ 进行 AOP 的开发: 注解的方式
<!-- 配置切面类 -->
<beanid="myAspectXml"class="cn.itcast.spring.demo3.MyAspectXml"></bean>
<!-- 进行aop的配置 -->
<aop:config>
<!-- 配置切入点表达式:哪些类的哪些方法需要进行增强 -->
<aop:pointcutexpression="execution(* cn.spring.demo3.*Dao.save(..))"id="pointcut1"/>
<aop:pointcutexpression="execution(* cn.spring.demo3.*Dao.delete(..))"id="pointcut2"/>
<aop:pointcutexpression="execution(* cn.spring.demo3.*Dao.update(..))"id="pointcut3"/>
<aop:pointcutexpression="execution(* cn.spring.demo3.*Dao.find(..))"id="pointcut4"/>
<!-- 配置切面 -->
<aop:aspectref="myAspectXml">
<aop:beforemethod="before"pointcut-ref="pointcut1"/>
<aop:after-returningmethod="afterReturing"pointcut-ref="pointcut2"/>
<aop:aroundmethod="around"pointcut-ref="pointcut3"/>
<aop:after-throwingmethod="afterThrowing"pointcut-ref="pointcut4"/>
<aop:aftermethod="after"pointcut-ref="pointcut4"/>
</aop:aspect>
</aop:config>
引入相关的 jar 包:
引入 Spring 的配置文件
引入 AOP 约束:
编写目标类:
<beansxmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
</beans>
配置目标类:
publicclassProductDao {
publicvoid save() {
System.out.println("保存商品...");
}
publicvoid update() {
System.out.println("修改商品...");
}
publicvoiddelete() {
System.out.println("删除商品...");
}
publicvoid find() {
System.out.println("查询商品...");
}
}
开启 aop 注解的自动代理:
<!-- 目标类============ -->
<beanid="productDao"class="cn.spring.demo4.ProductDao"></bean>
<aop:aspectj-autoproxy/>
AspectJ 的 AOP 的注解:
@Aspect: 定义切面类的注解
通知类型:
* @Before : 前置通知
* @AfterReturing : 后置通知
* @Around : 环绕通知
* @After : 最终通知
* @AfterThrowing : 异常抛出通知.
@Pointcut: 定义切入点的注解
编写切面类:
配置切面:
@Aspect
publicclassMyAspectAnno{
@Before("MyAspectAnno.pointcut1()")
publicvoid before(){
System.out.println("前置通知===========");
}
@Pointcut("execution(* cn.spring.demo4.ProductDao.save(..))")
privatevoid pointcut1(){}
}
其他通知的注解:
<!-- 配置切面类 -->
<beanid="myAspectAnno"class="cn.spring.demo4.MyAspectAnno"></bean>
spring-AOP 原理与应用
@Aspect
publicclassMyAspectAnno{
@Before("MyAspectAnno.pointcut1()")
publicvoid before(){
System.out.println("前置通知===========");
}
@AfterReturning("MyAspectAnno.pointcut2()")
publicvoid afterReturning(){
System.out.println("后置通知===========");
}
@Around("MyAspectAnno.pointcut3()")
publicObject around(ProceedingJoinPoint joinPoint)throwsThrowable{
System.out.println("环绕前通知==========");
Object obj = joinPoint.proceed();
System.out.println("环绕后通知==========");
return obj;
}
@AfterThrowing("MyAspectAnno.pointcut4()")
publicvoid afterThrowing(){
System.out.println("异常抛出通知========");
}
@After("MyAspectAnno.pointcut4()")
publicvoid after(){
System.out.println("最终通知==========");
}
@Pointcut("execution(* cn.itcast.spring.demo4.ProductDao.save(..))")
privatevoid pointcut1(){}
@Pointcut("execution(* cn.itcast.spring.demo4.ProductDao.update(..))")
privatevoid pointcut2(){}
@Pointcut("execution(* cn.itcast.spring.demo4.ProductDao.delete(..))")
privatevoid pointcut3(){}
@Pointcut("execution(* cn.itcast.spring.demo4.ProductDao.find(..))")
privatevoid pointcut4(){}
}
来源: http://www.bubuko.com/infodetail-2464976.html