目录
1.基本概念
2.AOP传统开发
2.1基于aspectj开发aop
3.aspectj注解开发
一、基本概念
- AOP
(1)Aspect Oritented Programming的缩写,面向切面编程。
(2)是通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。
(3)AOP是一个概念,没有设定具体的语言。它克服了那些只有单继承特性的语言的缺点。
spring2.0后整合了AspectJ的技术
- AspectJ
(1)是一个面向切面的框架。扩展了java语言,AspectJ定义了aop的语法,
所以它有一个专门的编译器用来生成遵守java的字节编码的规范的class文件
(2)aop:主要的功能:日志记录、性能统计、安全控制、事务处理、异常处理等。
(在调用service层的时候,进行一个横切,进行代理。然后再进行service层的触发。)
- AOP和OOP的区别
(1)oop:(面向对象编程)是对业务处理过程的实体、属性和行为进行抽象的封装,来获得更加清晰高效的逻辑单元划分。
(2)aop:(面向切面编程)是对业务处理过程中切面的提取。面对的是处理过程中的每一个步骤和阶段。以获得逻辑过程中的各部分之间的低耦合性的隔离效果,
- AOP的相关术语
(1)target ( 目标对象 ):指需要被增强的对象。 由于spring aop的通过代理模式实现的。这个对象永远都是被代理对象。
(2)join point ( 连接点 ): 指被拦截的点 ( 方法 ) ; spring支持方法类型的连接点。
(3)pointcut ( 切入点 ) : 指一组 join point ; 通过逻辑关系组合起来,或通过通配、正则表达式等方式集中起来。定义了相应的Advice将要发生的地方。
(4)advice ( 通知 ):就是拦截到连接点之后,需要做的事情。 通知分为前置通知、后置通知、异常通知、最终通知、环绕通知、定义了在pointcut 里面定义的程序点具体要做的操作。
(5)introduction ( 引介 ) : 是一种特殊的通知。在不修改类代码的前提下。可以在运行期间为类动态的添加一些方法或属性。
(6)aspect ( 切面 ) :是切入点和通知的结合。
(7)weaving ( 织入 ) : 是一个过程,是将切面应用到目标对象从而创建出aop代理对象的过程。 织入可以在编译期,类装载期,运行期进行。 spring使用动态织入。aspectJ使用静态织入。
(8)proxy ( 代理 ) : 一个类被aop织入增强后,就产生一个结果代理类。
- AOP的底层开发
AOP分为静态aop和动态aop。
静态aop:是指aspectJ实现的aop,将切面代码直接编译到java类文件中。
动态aop:是spring实现的aop,将切面动态的织入实现的aop。
实现技术:JDK动态代理、CGLIB动态代理。
JDK动态代理:在运行期间JVM会动态的生成class字节码对象(class对象) (只针对接口操作)
CGLIB动态代理 (Code Generation Library):是一个开源的项目。在运行期间扩展java类与实现java的接口。
CGLIB的底层是使用一个快而小的字节码框架ASM,来转换字节码并生成新的类。
如果是单独使用。侧需要导入:cglib、asm的jar包;但是使用spring来开发,侧需要导入spring-core的jar包。
返回顶部
二、AOP传统开发
需要导入核心jar包和依赖jar包
传统开发中有5种开发:org.springframework.aop.包下
- MethodBeforeAdvice:前置通知;
- AfterReturningAdivce:后置通知;
- MethodInterceptor:环摇通知;
- ThrowsAdivce:异常通知;
- IntroductionInterceptor:引介通知
传统的aop开发,需要每一步都手动创建,并实现。(例子)
因为;JDK动态代理是面对接口实现的。CGLIB动态代理是开源项目。
1、创建目标对象
(1)创建接口类:
public interface testaop { //一般的开发中都是会使用接口+实现类的这种开发模式的。
public void test1();
}
(2)创建实现类:
public class textaop implements testaop {
@Override
public void test1() {
System.out.println("我是一个target对象!");
}
}
2、创建通知类
注意: 这里使用的是“传统的aop的开发模式”。 所以,配置通知类的时候,需要进行“对应通知的接口的实现”。
//像这里,配置前置通知,需要实现MethodBeforeAdvice接口,重写里面的方法。
public class adviceed implements MethodBeforeAdvice {
@Override //除了前置通知。也可以配置其他通知。不过需要实现对应的接口类。
public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable {
System.out.println("我是前置通知!");
}
}
3、设置配置文件
注意:传统的aop开发。最繁杂的就是在配置文件中的配置。需要把每一个步骤都配置到配置文件中。这要spring就可以进行管理。
//(1) 配置target (目标对象);
<bean id="targeted" class="aop.textaop"></bean>
//(2)配置advice (通知类);
<bean id="adviced" class="aop.adviceed"></bean>
//(3) 配置pointcut (切入点);
<bean id="pointcuted" class="org.springframework.aop.support.NameMatchMethodPointcut">
<property name="mappedNames"> //这个mappedNames 是规定的元素。
<list>
<value>test1</value> //需要配置通知的方法名称
</list>
</property>
</bean>
注意:配置pointcut (切入点):也可以使用“正则表达式”的方法进行配置。
<bean id="调用名称" class="org.springframework.aop.support.JdkRegexpMethodPointcut">
//使用正则表达式, name : 是特定名称 ; value : 使用正则表达式
<property name="patterns" value=".*add"></property> </bean>
//(4)配置aspect(切面);
<bean id="aspected" class="org.springframework.aop.support.DefaultPointcutAdvisor">
<property name="advice" ref="adviced"></property> //注入 advice (通知)
<property name="pointcut" ref="pointcuted"></property> //注入pointcut(切入点)
</bean>
//(5)配置proxy(代理);
<bean id="proxyed" class="org.springframework.aop.framework.ProxyFactoryBean">
//name都为特定名称
<property name="target" ref="targeted"></property> // ref : 目标对象调用名称
<property name="interceptorNames" value="aspected"></property> // value : 切面调用名称
<property name="proxyInterfaces" value="aop.testaop"></property> // value: 接口类路径。
</bean>
5、Junit测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")public class tests {
@Autowired
@Qualifier("proxyed") //如果代理多个接口的时候。就需要指定一下。 “” 是接口 代理接口的调用名
private testaop aop;
@Test
public void test3() {
aop.test1();
}
}
返回顶部
基于aspectj开发aop
基于aspectJ开发,和传统的相比就是配置的时候,基于aspectJ。这样开发起来比较简单。
还需要导入aspectj的包。aspectJ.weaver的jar包
使用传统开发的接口和实现方法写基于aspectj开发aop:
//在spring配置文件中配置
//(1)配置target(目标对象)
<bean id="targeted" class="aop.textaop"></bean>
//(2)配置advice(通知)
<bean id="adviced" class="aop.adviceed"></bean>
//导入jar包后,使用 aop:config 标签 来 基于aspectJ的传统开发模式。
<aop:config>
//(3)配置pointcut(切面); expersion : 切点表达式; id : 是调用名
<aop:pointcut expression="execution(* *.test1(..))" id="pointcuted"/>
//(4)注入advice和pointcut ; advice-ref : 通知调用名 ; pointcut-ref: 切面调用名
<aop:advisor advice-ref="adviced" pointcut-ref="pointcuted"/> </aop:config>
返回顶部
三、aspectj注解开发
(1)编写目标类 – 接口实现类
(2)编写“实现类”和“增强”
(3)配置“注解扫描”和“aspectj注解自动代理”
几个注解:
- @Aspect (标记使用aspectj),
- @Pointcut (定义切点),
其他通知的注解:
- @Before(前置)、
- @After(后置)、
- @AfterReturning(返回)、
- @Around(环绕)、
- @AfterThrowing(异常)
- @Pointcut (定义切点)的优点:
其他通知引用方法名即可。且允许逻辑运算
aspectj代理方式:<aop:aspectj-autoproxy proxy-target-class=“true”>
proxy-target-class默认值是false,表示如果目标类有接口就使用jdk的proxy代理。如果没有就使用cglib代理。
如果设置为true,不管有没有接口,都会使用cglib来代理。
//(1)定义目标类
public interface Person{//人类
public void eat();
public void play();
}
//(2)实现类
public class xiaoming implements Person{
@Override
public void eat(){
System.out.println("吃水果");
}
@Override
public void eat(){
System.out.println("打篮球");
}
}
//(3)编写增强类
@Component
@Aspect
public class AdivceMethod{
//配置前置通知
@Before("execution(* *.e*(..))")
public void eatbefore(){
System.out.println("吃饭前要洗手");
}
//扩展:@Pointcut的使用
//配置切点
@Pointcut("execution(* *.e*(..))")
public void pointcut1(){
System.out.println("吃饭的时候要告诉妈妈");
}
@Pointcut("execution(* *.p*(..))")
public void pointcut2(){
System.out.println("玩的时候要告诉妈妈");
}
//这样就可以使用@Pointcut的有点
@Before(pointcut1() || pointcut2())
public void before(){
System.out.println("前置通知");
}
}
//(4)配置注解和代理
//在spring配置文件中
<context:component-scan base-package="text"/> //配置注解扫描包
<aop:aspectj-autoproxy proxy-target-class="false"/> //配置代理方式
一些aspectj的正则表达式:
- execution( public * *() ) :表示所有public的方法
- execution(* com.aop.*(…) ) :所有aop包里面的方法(不包含子包)
- execution(* com.aop…*(…) ) : 所有aop包里面的方法(含子包)
- execution(* com.aop.jk.*(…) ) : 接口jk中所有的方法
- execution(* com.aop.jk+.*(…) ) : 接口jk中所有实现类的方法
- execution(* s*(…)) : 所有以s开头的方法
返回顶部