spring aop
aop中包含了通过接口实现的JDK动态代理 和 通过目标类实现的cglib代理
java 动态代理--JDK动态代理只能对实现了接口的类生成代理,而不能针对类 ,通过实现InvocationHandler接口来代理类。
代理分为静态代理和动态代理,静态代理是在编译时就将接口、实现类、代理类一股脑儿全部手动完成,
但如果我们需要很多的代理,每一个都这么手动的去创建实属浪费时间,而且会有大量的重复代码,
此时我们就可以采用动态代理,动态代理可以在程序运行期间根据需要动态的创建代理类及其实例,
来完成具体的功能。
其实方法直接调用就可以完成功能,为什么还要加个代理呢?
原因是采用代理模式可以有效的将具体的实现与调用方进行解耦,通过面向接口进行编码完全将具体的实现隐藏在内部。
CGLIB--代理类通过MethodInterceptor接口实现代理
cglib是一个高性能的代码生成包
CGLIB可以在运行期扩展Java类与实现Java接口,cglib封装了asm,可以在运行期动态生成新的 class,cglib用于AOP,
jdk中的代理必须基于接口,cglib却没有这个限制。
ASM---
ASM是一个Java字节码操纵框架,它能被用来动态生成类或者增强既有类的功能。ASM可以直接产生二进制class文件,
也可以在类被加载入Java虚拟机之前动态改变类行为。Java class被存储在严格格式定义的.class文件里,
这些类文件拥有足够的元数据来解析类中的所有元素:类名称、方法、属性以及 Java 字节码(指令)。
ASM从类文件中读入信息后,能够改变类行为,分析类信息,甚至能够根据用户要求生成新类。
AspectJ--aop通过注解@AspectJ来实现
AspectJ是一个面向切面的框架,
AspectJ是一个代码生成工具(Code Generator),有一个用来生成遵守Java字节编码规范的Class文件的编译器。
AspectJ语法就是用来定义代码生成规则的语法。
AspectJ的表达式实例--
execution(public * *(..)):任意public方法
execution(public * com.mycompany..*.*(..)):com.mycompany包下任意子包的所有类的所有public 方法
大致运行过程
一、AspectJ从文件列表里取出所有的文件名,然后读取这些文件,进行分析。
二、AspectJ发现一些文件含有aspect的定义
三、AspectJ根据这些aspect代码生成规则,修改添加你的源代码。
未修改前
public static void main(String args[])
{
Speaker speaker = new Speaker();
speaker.speak();
}
修改后的源代码
public static void main(String args[])
{
Speaker speaker = new Speaker();
AspectObserver.aspectOf().ajc$before$test_aspectj_AspectObserver$1$b2b6354();//多了这行
speaker.speak();
AspectObserver.aspectOf().ajc$afterReturning$test_aspectj_AspectObserver$2$b2b6354();//多了这行
}
SpringAop全自动代理实例
/**
* 测试类
* @author Administrator
*
*/
public void test() {
//启动spring上下文环境
ApplicationContext context = new ClassPathXmlApplicationContext("spring/spring.xml");
SayHello hello = (SayHello) context.getBean("sayHelloImpl");
hello.sayHello("aaa");
}
/**
* 测试接口
* @author Administrator
*
*/
public interface SayHello {
public void sayHello(String name);
}
/**
* 全自动AOP代理
* @author Administrator
*
*/
@Component
public class SayHelloImpl implements SayHello {
@Override
public void sayHello(String name) {
System.out.println("你好"+name);
}
}
/**
* 自定义切面
* Aspect是一个用java实现的解决advice使用太麻烦问题
* Aspect:多个advice+多个连接点和切入点-最后执行表达式
* @author Administrator
*
*/
@Aspect
@Component
public class MyAspect {
public MyAspect() {
}
//环绕通知
@Around("execution(* com.yd.autoProxy.SayHelloImpl.*(..))")
public Object aroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable{
beforeAdvice();
Object object = joinPoint.proceed();
afterAdvice();
return object;
}
private void beforeAdvice(){
System.out.println("环绕前置增强");
}
private void afterAdvice(){
System.out.println("环绕后置增强");
}
}
//xml配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd">
<!-- 扫描包加载实现类 -->
<context:component-scan base-package="com.yd.autoProxy"></context:component-scan>
<aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>
</beans>
打印结果
环绕前置增强
你好aaa
环绕后置增强