Java -面向切面编程(AOP)

第一节 AOP 简介

Aspect-Oriented-Programming(面向切面编程)

一种编程思想。

切面:Aspect,由切入点额外功能(增强)组成

作用:提供了新的编程角度,不再只是考虑类、对象,而可以考虑切面。切面和目标形成 代理,解决项目业务中额外功能冗余的问题。

  1. 业务中存在的问题:业务层中存在问题:两类逻辑=核心业务+额外功能,其中额外功能存在大量的代码冗余 。使得项目维护存在极大隐患。
    例如:
class UserServiceImpl implements UserService{
	private UserDAO ud;
    public void updateUser(User user){
        System.out.println("事务管理功能");//额外功能 冗余
        ud.update(user); //核心功能
    }
    public void inserUser(User user){
        System.out.println("事务管理功能");//额外功能 冗余
        ud.insertUser(user);//核心功能
    }
    public User queryUser(Integer id){
        System.out.println("事务管理功能");//额外功能 冗余
        ud.queryUser(id);//核心功能
    }
}

以上代码出现了大量的冗余。

动态代理:

通过动态字节码技术,在运行时动态生成代理( 反射 )。

则既不用维护代理类,有可以有代码打理额外功能。

动态代理的实现方案:

  • jdk代理 ( jdk在反射包中提供的一套api ) 通过和目标实现相同的接口保证功能一致
  • cglib代理 ( 第三方cglib库中的一套api ) 通过继承目标保证功能一致

第二节 AOP 编码流程

第一步 :导入依赖

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context-support</artifactId>
    <version>4.3.6.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aspects</artifactId>
    <version>4.3.6.RELEASE</version>
</dependency>

第二步 准备 Target

public class UserServiceImpl implements UserService{
    private UserDAO userDAO;
    // set/get...
    @Override
    public void updateUser(User user) {
        System.out.println("update in service==========");
        userDAO.updateUser(user);
    }
    @Override
    public void insertUser(User user) {
        System.out.println("insert in service===============");
        userDAO.insertUser(user);
    }
}

第三步 准备 Advice

public class MyBeforeAdvice implements MethodBeforeAdvice{

    /**
     * @param method 当前执行的方法
     * @param args   当前执行的方法中的参数
     * @param target 目标对象
     * @throws Throwable
     */
    @Override
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println("before~~~");
    }
}

第四步 编织 Weave
所谓编织,即,将Target 和 Advice 组装 形成代理。**

当然组装过程由spring管理,开发者只需要做出配置,告知spring需要组装谁即可

<!-- 声明 Target + Advice -->
<!-- 声明 Target -->
<bean id="userService" class="com.zhj.service.UserServiceImpl">
    <!-- 为userDAO属性赋值,值为id=“userDAO”的组件 -->
    <property name="userDAO" ref="userDAO"/>
</bean>


<!-- Advice -->
<bean id="myBefore" class="com.zhj.advice.MyBeforeAdvice"/>



<!-- 编织 配置 -->
<aop:config>
         <!-- ref="引入MyAdvice" -->
          <aop:aspect ref="myAdvice">
        <!-- 切入点=pointcut
 			execution()表达式:描述切入位置
            组成:修饰符   返回值      包      类  方法名  参数表
            
        <aop:pointcut id="pc" expression="execution(* com.service.UserServiceImpl.queryUser(..))"/>
     
        <aop:advisor advice-ref="myBefore" pointcut-ref="pc"/>
    </aop:aspect>
</aop:config>

多种Advice

一 、 后置额外功能

package com.vince.advice;

import org.springframework.aop.AfterReturningAdvice;

import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.Date;

public class MyafterAdvice implements AfterReturningAdvice {


    @Override
    public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
        Date date = new Date();
        SimpleDateFormat sd = new SimpleDateFormat("yy-MM-dd HH:mm:ss");
        String da = sd.format(date);
        System.out.println("于"+da+"之后 切入额外功能...");
    }
}

二 、前置额外功能

package com.vince.advice;

import org.springframework.aop.MethodBeforeAdvice;

import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.Date;

public class MyBeforeAdvice implements MethodBeforeAdvice {


    @Override
    public void before(Method method, Object[] args, Object target) throws Throwable {

        Date date = new Date();
        SimpleDateFormat sd = new SimpleDateFormat("yy-MM-dd HH:mm:ss");
        String da = sd.format(date);
        System.out.println("于"+da+"之前 切入额外功能...");

    }
}

三 、 环绕额外功能

package com.vince.advice;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

public class MyMethodInterceptor implements MethodInterceptor {
    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {

        System.out.println("环绕前.....");

        Object ret = invocation.proceed();   //执行目标业务方法

        System.out.println("环绕后");
        return ret;
    }
}

四、异常额外功能(了解)

public class MyThrows implements ThrowsAdvice{
    //目标业务方法中抛出异常时,执行此方法。ex=抛出的异常对象
    public void afterThrowing(Exception ex){
        System.out.println(ex.getMessage()+"~~~");
    }
}

*** 切入点表达式:

一、execution

1> * com.service.UserServiceImpl.queryUser(..)
    修饰符:任意
    返回值:任意
    包:com.service
    类:UserServiceImpl
    方法:queryUser
    参数表:任意
2> * com.service.UserServiceImpl.*(..)
    修饰符:任意
    返回值:任意
    包:com.service
    类:UserServiceImpl
    方法:所有,任意
    参数表:任意
3> * com..UserServiceImpl.*(..)
    修饰符:任意
    返回值:任意
    包:com包,及其子包
    类:UserServiceImpl
    方法:所有,任意
    参数表:任意
4> * com.service.*.*(..)
    修饰符:任意
    返回值:任意
    包:com.service
    类:所有,任意
    方法:所有,任意
    参数表:任意
5> * *(..)    不建议
    修饰符:任意
    返回值:任意
    包:任意
    类:所有,任意
    方法:所有,任意
    参数表:任意
6> * com.service.UserServiceImpl.query*(..)  【技巧:批量切入】
    修饰符:任意
    返回值:任意
    包:com.service
    类:UserServiceImpl
    方法:所有,任意
    参数表:任意
  *注意:尽量精确,避免不必要的切入

二、within
描述中所有方法都切入

示例:`within(com.service.UserServiceImpl) 类中的所有方法

within(com…UserServiceImpl) com包和com子包下的类中的所有方法

<aop:pointcut id=“pc” expression=“within(com…UserServiceImpl)”/>

三、args
描述参数表,符合的方法都切入

args(int,String,com.entity.User) 参数表如此的方法

<aop:pointcut id=“pc” expression=“args(int,String,com.entity.User)”/>

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值