您的位置:首页 > 编程语言 > Java开发

spring 详解AOP

2016-04-16 21:47 513 查看
什么是AOP?

先了解什么是OOP 

OOP(Object-Oriented Programing,面向对象编程)

OOP引入封装、继承和多态性等概念来建立一种对象层次结构,用以模拟公共行为的一个集合。

当我们需要为分散的对象引入公共行为的时候,OOP则显得无能为力。

OOP允许你定义从上到下的关系,但并不适合定义从左到右的关系。

例如日志功能。日志代码往往水平地散布在所有对象层次中,而与它所散布到的对象的核心功能毫无关系。对于其他类型的代码,如安全性、异常处理和透明的持续性也是如此。这种散布在各处的无关的代码被称为横切(cross-cutting)代码,在OOP设计中,它导致了大量代码的重复,而不利于各个模块的重用。

    
AOP(Aspect-OrientedProgramming,面向方面编程)

AOP技术刚好相反;它利用一种称为“横切”的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其名为“Aspect”,即方面。所谓“方面”,简单地说,就是将那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可操作性和可维护性。

AOP把软件系统分为两个部分:核心关注点和横切关注点。

核心关注点:业务处理的主要流程;

横切关注点:与业务主要流程关系不大的部分;

横切关注点特点:他们经常发生在核心关注点的多处,而各处都基本相似。比如权限认证、日志、事务处理。

Aop
的作用在于分离系统中的各种关注点,将核心关注点和横切关注点分离开来。

AOP的核心思想就是“将应用程序中的商业逻辑同对其提供支持的通用服务进行分离。”

好了说了那么多用用看吧!

先了解AOP的相关术语:
1.通知(Advice):
通知定义了切面是什么以及何时使用。描述了切面要完成的工作和何时需要执行这个工作。
2.连接点(Joinpoint):
程序能够应用通知的一个“时机”,这些“时机”就是连接点,例如方法被调用时、异常被抛出时等等。
3.切入点(Pointcut)
通知定义了切面要发生的“故事”和时间,那么切入点就定义了“故事”发生的地点,例如某个类或方法的名称,

Spring中允许我们方便的用正则表达式来指定
4.切面(Aspect)
通知和切入点共同组成了切面:时间、地点和要发生的“故事”
5.引入(Introduction)
引入允许我们向现有的类添加新的方法和属性(Spring提供了一个方法注入的功能)
6.目标(Target)
即被通知的对象,如果没有AOP,那么它的逻辑将要交叉别的事务逻辑,有了AOP之后它可以只关注自己要做的事(AOP让他做爱做的事)
7.代理(proxy)
应用通知的对象,详细内容参见设计模式里面的代理模式
8.织入(Weaving)
把切面应用到目标对象来创建新的代理对象的过程,织入一般发生在如下几个时机:
(1)编译时:当一个类文件被编译时进行织入,这需要特殊的编译器才可以做的到,例如AspectJ的织入编译器
(2)类加载时:使用特殊的ClassLoader在目标类被加载到程序之前增强类的字节代码
(3)运行时:切面在运行的某个时刻被织入,SpringAOP就是以这种方式织入切面的,原理应该是使用了JDK的动态代理技术

Spring提供了4种实现AOP的方式:
1.经典的基于代理的AOP
2.@AspectJ注解驱动的切面
3.纯POJO切面
4.注入式AspectJ切面

基于代理的AOP:

Spring支持五种类型的通知:
Before(前)  org.apringframework.aop.MethodBeforeAdvice
After-returning(返回后) org.springframework.aop.AfterReturningAdvice
After-throwing(抛出后) org.springframework.aop.ThrowsAdvice
Arround(周围) org.aopaliance.intercept.MethodInterceptor
Introduction(引入) org.springframework.aop.IntroductionInterceptor

荔枝中只使用  Before(前)  org.apringframework.aop.MethodBeforeAdvice
After-returning(返回后) org.springframework.aop.AfterReturningAdvice

具体步骤:

  1.创建通知:对象实现功能接口,创建通知;

  2.定义切点和advisor;

  3.用ProxyFactoryBean生成代理;

-1-创建接口StudyAble 学习能力的接口;

package spring.aop.bean;

/**
* 关于学习的一些功能
*/
public interface StudyAble {
void study();
}


  写一个Programmer类来实现StudyAble接口;
package spring.aop.bean;

/**
* 程序猿一个神奇的物种通过学习能获得金钱¥¥
*/
public class Programmer implements StudyAble{
@Override
public void study() {
System.out.println("学习就是涨工资!!!");
}
}


但是在学习前后都是需要做准备的,比如说放松放松!或者其他的什么事情但是这不是核心关注点,核心关注点还是学习;就放松这个行为来看是不仅仅是程序员需要去做的学生学习也要放松老师学习也需要放松,但是他们学习的实现确实不同的同事也说核心的,所以放松也很重要;
package spring.aop.bean;

import org.springframework.aop.AfterReturningAdvice;
import org.springframework.aop.MethodBeforeAdvice;

import java.lang.reflect.Method;

/**
* 在学习前后需要做的事情
*/
public class StudyHelper implements MethodBeforeAdvice,AfterReturningAdvice{

@Override
public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
System.out.println("学习后要放松!!!");
}

@Override
public void before(Method method, Object[] objects, Object o) throws Throwable {
System.out.println("学习前要放松!!!");
}
}


--2--spring文件中的配置;
创建程序员配置:

<bean id="Programmer" class="spring.aop.bean.Programmer">
</bean>

创建通知配置:
<bean id="studyHelper" class="spring.aop.bean.StudyHelper">
</bean>

使用正则表达式配置切点:pattern属性指定了正则表达式,它匹配所有的study方法
<bean id="studyPointcut" class="org.springframework.aop.support.JdkRegexpMethodPointcut">
<property name="pattern" value=".*study"/>
</bean>将通知和切点结合起来,就是通知者了:
<bean id="studyHelperAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
<property name="advice" ref="studyHelper"/>
<property name="pointcut" ref="studyPointcut"/>
</bean>

--3--使用代理对象来实现接口中的代理对象:
<bean id="ProgrammerProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="Programmer"/>
<property name="interceptorNames" value="studyHelperAdvisor"/>
<property name="proxyInterfaces" value="spring.aop.bean.StudyAble"/>
</bean>

测试:
package spring.aop.bean;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
*/
public class Test {
public static void main(String[] args){
ApplicationContext ap = new ClassPathXmlApplicationContext("applicationContext.xml");
StudyAble studyAble = (StudyAble)ap.getBean("ProgrammerProxy");
studyAble.study();
}
}

学习前要放松!!!
学习就是涨工资!!!
学习后要放松!!!


利用自动代理进行配置(将之前手动配置代理主调):
<!--<bean id="ProgrammerProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="Programmer"/>
<property name="interceptorNames" value="studyHelperAdvisor"/>
<property name="proxyInterfaces" value="spring.aop.bean.StudyAble"/>
</bean>-->

<!--自动代理配置-->
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>


测试:
package spring.aop.bean;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
*/
public class Test {
public static void main(String[] args){
ApplicationContext ap = new ClassPathXmlApplicationContext("applicationContext.xml");
StudyAble studyer = (StudyAble)ap.getBean("Programmer");
studyer.study();
}
}


结果:
学习前要放松!!! 学习就是涨工资!!! 学习后要放松!!!

在使用AspectJ注解来做的时候出现问题:

创建programmer类:

package spring.aop.bean;
/**
* 程序猿一个神奇的物种通过学习能获得金钱¥¥
*/
pu
9e65
blic class Programmer implements StudyAble{
@Override
public void study() {
System.out.println("学习就是涨工资!!!");
}
}
study功能接口:
package spring.aop.bean;
/**
* 关于学习的一些功能
*/

public interface StudyAble {
void study();
}
切面Aspect类创建:
package spring.aop.bean;

import org.aspectj.lang.annotation.*;

/**
*
*/
@Aspect
public class AspceJAdvice {
@Pointcut("execution(* *.study())")
public void aspce(){};

@Before("aspce()")
public void beforeAdvice(){
System.out.println("before");
}

@AfterReturning("aspce()")
public void afterAdvice(){
System.out.println("after");
}
}

spring文件配置:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="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-3.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
<aop:aspectj-autoproxy/>
<bean id="programmer" class="spring.aop.bean.Programmer">
</bean>
<bean id="aspcejHandler" class="spring.aop.bean.AspceJAdvice">
</bean>
</beans>


测试文件:
package spring.aop.bean;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
*/
public class Test {
public static void main(String[] args){
ApplicationContext ap = new ClassPathXmlApplicationContext("applicationContext.xml");
Programmer programmer = (Programmer)ap.getBean("programmer");
programmer.study();
}
}


但是运行一直都报错:
警告: Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'programmer' defined in class path resource [applicationContext.xml]: Initialization of bean failed; nested exception is java.lang.IllegalArgumentException: error at ::0 can't find referenced pointcut aspce
Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'programmer' defined in class path resource [applicationContext.xml]: Initialization of bean failed; nested exception is java.lang.IllegalArgumentException: error at ::0 can't find referenced pointcut aspce

Caused by: java.lang.IllegalArgumentException: error at ::0 can't find referenced pointcut aspce


更新了


aspectjweaver.jar 和aspectj 后还是报错就不知道是什么原因了;

有大牛看出问题啦就指点一二吧,感激不敬!!!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: