Spring第二天(AOP)

2017-07-19  本文已影响0人  原来蜗牛不是牛

什么是AOP?

AOP(Aspect Orient Programming),也就是面向切面编程,作为面向对象编程的一种补充,已经成为一种比较成熟的编程方式。AOP和OOP互为补充,面向对象编程将程序分解成各个层次的对象,而面向切面编程将程序运行过程分解成各个切面。可以这样理解:面向对象编程是从静态角度考虑程序结构,而面向切面编程是从动态角度考虑运行过程

AOP的基本概念

  1. AOP从程序运行角度考虑程序的流程,提取业务处理过程的切面。AOP面向的是程序运行中各个步骤,希望以更好的方式来组合业务处理的各个步骤。
  2. AOP框架并不与特定的代码耦合,AOP框架能处理程序执行中特定的切入点(Pointcut),而不与某个具体类耦合。AOP具有如下两个特征:
  1. 关于面向切面编程的一些术语

如何使用表达式来定义切入点是AOP的核心,Spring默认使用AspectJ切入点语法。

关系图如下:

AOP关系图

AOP的基本操作

  1. 为什么使用AOP
    业务场景:
    服务层:提供30个模块的服务。同时这些模块都依赖某个或某几个公共服务。(事务管理,日志管理。)
    传统方式:使用继承的方式
    将子类公有需要执行的方法抽取成一个父类,在使用到公共方法的地方去调用父类的方法
    AOP目的:程序员能够安心做业务成的业务
  2. 使用AOP之最最最原始的步骤
public interface StudentService {
    void addStudent();
    void delStudent();
    void updateStudent();
    String findStudent();
}

业务层实现类:

public class StudentServiceImpl implements StudentService {

    @Override
    public void addStudent() {
        System.out.println("addStudent");

    }

    @Override
    public void delStudent() {
        System.out.println("delStudent");

    }

    @Override
    public void updateStudent() {
        System.out.println("updateStudent");
    }

    @Override
    public String findStudent() {
        // TODO Auto-generated method stub
        return "haha";
    }
}
import java.lang.reflect.Method;
import org.springframework.aop.MethodBeforeAdvice;
public class LogAdvice implements MethodBeforeAdvice {

    @Override
    public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable {
        System.out.println("前置通知,日志记录");
        
    }
}

环绕通知:

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
public class AroundAdvice implements MethodInterceptor {

    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        System.out.println("环绕前");
        //回调原来的目标方法
        Object proceed = invocation.proceed();//上面的代码在调用目标方法之前执行,下面的代码在调用目标方法后执行
        System.out.println("环绕后");
        return proceed;
    }
}

后置通知:在调用目标方法后执行

import java.lang.reflect.Method;
import org.springframework.aop.AfterReturningAdvice;
public class TestAdvice implements AfterReturningAdvice {

    @Override
    public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
        System.out.println("后置通知返回值:"+returnValue);
        
    }
}
<!-- 1.创建目标类对象 -->
    <bean id="studentService" class="org.cx.service.StudentServiceImpl" ></bean>
    <!-- 2.创建通知类对象 -->
    <!-- <bean id="logAdvice" class="com.cx.advice.LogAdvice" ></bean>
    <bean id="testAdvice" class="com.cx.advice.TestAdvice" ></bean> -->
    <bean id="aroundAdvice" class="com.cx.advice.AroundAdvice" ></bean>
    <!-- 3.创建Spring的代理类对象 -->
    <bean id="studentServiceProxy" class="org.springframework.aop.framework.ProxyFactoryBean" >
        <!-- aop编程整合 -->
        <!-- 1.整合目标类 -->
        <property name="target" ref="studentService"></property>
        <!-- 2.整合通知类 -->
        <property name="interceptorNames">
            <list>
                <!-- <value>logAdvice</value>
                <value>testAdvice</value> -->
                <value>aroundAdvice</value>
            </list>
        </property>
        <!-- 3.整合接口关联 -->
        <property name="proxyInterfaces" value="org.cx.service.StudentService"></property>
    </bean>

自动配置

<!-- 1.创建目标类对象 -->
    <bean id="studentService" class="com.cx.service.StudentServiceImpl" ></bean>
    <!-- 2.创建通知类对象 -->
    <!-- <bean id="logAdvice" class="com.cx.advice.LogAdvice" ></bean>
    <bean id="testAdvice" class="com.cx.advice.TestAdvice" ></bean> -->
    <bean id="aroundAdvice" class="com.cx.advice.AroundAdvice" ></bean>
    <!-- 3.自动方式配置AOP -->
    <aop:config>
        <!-- 1.配置扫描的服务层 
            切入点表达式:扫描到具体的方法
            * com.cx.service.*.*(..)
            * 返回类型 任意类型
            com.cx.service 服务层的包名
            第一个.*包下面的所有类
            第二个.*(..)类里面的所有方法-->
        <aop:pointcut expression="execution(* com.cx.service.*.*(..))" id="mypoint"/>
        <!-- 2.让服务层通知关联 -->
        <aop:advisor advice-ref="aroundAdvice" pointcut-ref="mypoint"/>
    </aop:config>
public static void main( String[] args )
    {
        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
        StudentService studentService = ac.getBean("studentServiceProxy",StudentService.class);
        studentService.addStudent();
        //studentService.findStudent();
    }

使用自动配置的测试:

public static void main( String[] args )
    {
        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
        StudentService studentService = ac.getBean("studentService",StudentService.class);
        studentService.addStudent();
        //studentService.findStudent();
    }

使用AspectJ框架进行AOP编程

AspectJ的通知和原始通知不同:不需要单独去实现接口,所有通知方法写在一个类

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
public class MyAdvice {
    //aspectj包下的
    //前置通知
    public void myBefore(JoinPoint jp){
        System.out.println("前置通知");
    }
    
    public Object myAround(ProceedingJoinPoint pjp) throws Throwable{
        System.out.println("环绕前");
        //手动执行目标方法
        Object proceed = pjp.proceed();
        System.out.println("环绕后");
        return proceed;
    }
    
    public void myAfter(JoinPoint jp,Object res){
        System.out.println("后置通知:"+res);
    }
}
public interface UserService {
    void addUser();
    
    void delUser();
    
    void updateUser();
    
    String findUser();
}

实现类

public class UserServiceImpl implements UserService {

    @Override
    public void addUser() {
        System.out.println("addUser");
    }

    @Override
    public void delUser() {
        System.out.println("delUser");

    }

    @Override
    public void updateUser() {
        System.out.println("updateUser");

    }

    @Override
    public String findUser() {
        return "美好的一天从微笑开始";
    }
}
<!-- 1.创建目标类对象 -->
    <bean id="userService" class="com.cx.service.UserServiceImpl" ></bean>
    <!-- 2.创建通知类对象 -->
    <!-- <bean id="logAdvice" class="com.cx.advice.LogAdvice" ></bean>
    <bean id="testAdvice" class="com.cx.advice.TestAdvice" ></bean> -->
    <bean id="myAdvice" class="com.cx.advice.MyAdvice" ></bean>
    <!-- 3.AspectJ的AOP编程 
        a.有一个AspectJ单独的节点
        b.通知也有单独的节点-->
    <aop:config>
        <aop:aspect ref="myAdvice">
            <!-- 扫描方法:定义切入点表达式 -->
            <aop:pointcut expression="execution(* com.cx.service.*.*(..))" id="mypoint"/>
            <!-- 配置前置通知 -->
            <!-- <aop:before method="myBefore" pointcut-ref="mypoint"/> -->
            <!-- 配置环绕通知 -->
            <!-- <aop:around method="myAround" pointcut-ref="mypoint"/> -->
            <!-- 配置后置通知 -->
            <aop:after-returning method="myAfter" pointcut-ref="mypoint" returning="res"/>
        </aop:aspect>
    </aop:config>

AspectJ使用注解的方式配置

public interface CarService {
    void addCar();
    String findCar();
}

实现类

import org.springframework.stereotype.Service;
@Service("carService")
public class CarServiceImpl implements CarService {
    @Override
    public void addCar() {
        System.out.println("addCar");
        
    }

    @Override
    public String findCar() {
        // TODO Auto-generated method stub
        return "风驰天下,大运摩托";
    }
}
@Component("myCarAspect")
@Aspect
public class MyCarAspect {
    //定义切入点表达式
    @Pointcut("execution(* com.cx.service.*.*(..))")
    public void myPoint(){
        
    }
//  @Before("myPoint()")//前置通知
//  public void myCarBefore(JoinPoint jp){
//      System.out.println("前置通知:美好的一天从绿色开始");
//  }
    
    @Around("myPoint()")//环绕通知
    public Object myAround(ProceedingJoinPoint pjp) throws Throwable{
        System.out.println("环绕前");
        //手动执行目标方法
        Object proceed = pjp.proceed();
        System.out.println("环绕后");
        return proceed;
    }
}
<!-- 开启注解扫描 -->
<context:component-scan base-package="com.cx"></context:component-scan>
    <!-- 开启AspectJ的注解 -->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
上一篇 下一篇

猜你喜欢

热点阅读