AOP

    AOP相关概念

【场景描述】

         结合前面的编码实操,已经解决了最初需求,推而广之,我们将纵向的从上到下的主要业务逻辑成为主线关注,如上面对User的CRUD操作;将增加日志记录、安全检查等横向性的问题,可以喝主线业务分离分开的称为(参考代理模式篇)

横切性关注点

AOP编程也就是基于上述描述推演开来。

1)       横切性关注点

我们加在主线业务前后的这些内容称为“横切性关注点”。根据OOP编程的原则,提供给多个地方调用的内容需要将它封装为一个方法,方法也不可能单独存在,需要存在一个类中,有此引出了后续概念。

 

2)       通知(advice)

将横向业务内容也即横切性关注点的内容封装为一个方法,这个方法称为“通知”advice

,它可以放在主方法的前面(比如User里面的add方法是主方法而checkSecurity可以放在add方法前面后面等,均可)也可以放在后面。除此外还有异常通知、环绕通知和最终通知。

被方法化的横切性关注点称为通知,它可以放在前后等多个地方。

 

3)       连接点(joinpoint)

就是那些被拦截到的点,spring这些点就是方法。也就是主线业务中的主要方法,每一

方法就是一个连接点,比如User类的CRUD四个方法,就是4个连接点。

 

4)       切入点(pointcut)

就是要对那些方法进行拦截,是对需要拦截的jonitpoint的定义。

 

5)       切面(aspect)

一个个封装了的方法称为advice,每一个方法均应该封装在一个类中;此外,在

这些advice上也需要定义将这些通知用于那些方法前面或者后面,这些定义也封装在这个类中,称为切入点,它们以后就作用于joinpoint将这些统一封装起来的类称为切面。公式表达:aspect=pointcut+advice

 

6)       织入(weave)

将aspect运用到代理的目标对象上并导致proxy创建的过程称为织入。

 

1.2       使用Spring进行AOP编程

1.2.1   用注解配置方式进行AOP开发

1)      首先启动对@AspectJ注解的支持以及XML的配置文件

<?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:context="http://www.springframework.org/schema/context"

       xmlns:aop="http://www.springframework.org/schema/aop"

       xmlns:tx="http://www.springframework.org/schema/tx"

    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd

http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd

http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd

http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">

    <!-- 首先启动对@AspectJ注解的支持 -->

<aop:aspectj-autoproxy/>

<bean id="myAspect" class="com.ailk.test.MyAspect"/>

<bean id="userServiceImpl" class="com.ailk.service.impl.UserServiceImpl"/>

</beans>

2)      进行Aspect内部通知和切入点的配置

import org.aspectj.lang.ProceedingJoinPoint;

import org.aspectj.lang.annotation.After;

import org.aspectj.lang.annotation.AfterReturning;

import org.aspectj.lang.annotation.AfterThrowing;

import org.aspectj.lang.annotation.Around;

import org.aspectj.lang.annotation.Aspect;

import org.aspectj.lang.annotation.Before;

import org.aspectj.lang.annotation.Pointcut;

 

@Aspect

publicclass MyAspect

{

    //声明一个切入点并配置,UserServiceImpl类中的delete方法进行拦截

    @Pointcut("execution (* com.ailk.service.impl.UserServiceImpl.delete(..))")

    privatevoid anyMethod() {}

   

   

    @Before("anyMethod()")

    publicvoid checkSecurity()

    {

       System.out.println(" 前置通知,安全检查---------");

    }

    @AfterReturning("anyMethod()")

    publicvoid checkSecurityAfterReturning()

    {

       System.out.println(" 后置通知,安全检查---------");

    }

    @After("anyMethod()")

    publicvoid checkSecurityAfter()

    {

       System.out.println(" 最终通知,安全检查---------");

    }

    @AfterThrowing("anyMethod()")

    publicvoid checkSecurityAfterThrowing()

    {

       System.out.println(" 例外通知,安全检查---------");

    }  

    @Around("anyMethod()")

    public Object checkSecurityAround(ProceedingJoinPoint pjp) throws Throwable

    {

       System.out.println(" 环绕通知进入**************************");

       Object obj = pjp.proceed();

       System.out.println(" 环绕通知结束**************************");

       return obj;

    }  

/* 【方法输入参数的精细化定义,按照输入参数匹配】

     * 最上面的pointcut定义了对com.ailk.service.impl.UserServiceImpl.delete类包下的

     * delete方法有效它可以接受任何参数,下面是更精细化的配置,要求输入

     * 参数还要有long uuid,String name两个才行,可以当做是delete(long uuid,String name)

     * 这样的方法才起效。

     * */

    @Before("anyMethod() && args(uuid,name)")

    publicvoid checkSecurity(long uuid,String name)

    {

       System.out.println(" 前置通知,安全检查有参数---------");

    }  

    /* 【方法输入参数的精细化定义,通过切面获得方法的返回值】

     * 最上面的pointcut定义了对com.ailk.service.impl.UserServiceImpl.delete类包下的

     * delete方法有效它可以接受任何参数,下面是更精细化的配置,要求方法返回值的必须是String类型

     * 的才起效且可以捕捉到方法调用时的返回值。

     * */ 

    @AfterReturning(pointcut="anyMethod()",returning="retValue")

    publicvoid checkSecurityAfterReturning(String retValue)

    {

       System.out.println(" 后置通知,安全检查---------"+retValue);

    }

}

 

 

 

import com.ailk.interfaces.UserService;

import com.ailk.po.User;

 

publicclass UserServiceImpl implements UserService {

    publicvoid add(User user){

       System.out.println("add用户成功");

    }

    publicvoid delete(long uuid){

        //int number = 10/0;

       System.out.println("delete用户成功");

    }

    publicvoid update(long uuid){

       System.out.println("update用户成功");

    }

    publicvoid getUserInfo(long uuid){

       System.out.println("getUserInfo用户成功");

    }

}

 

import org.springframework.context.ApplicationContext;

import org.springframework.context.support.ClassPathXmlApplicationContext;

 

import com.ailk.interfaces.UserService;

import com.ailk.po.User;

 

publicclass Test4

{

    publicstaticvoid main(String[] args) {

       User user = new User();

       user.setName("张三");

       user.setPassword("1234");

      

       ApplicationContext ac = new ClassPathXmlApplicationContext("AOP.xml");

       UserService service = (UserService) ac.getBean("userServiceImpl");

       service.add(user);

       System.out.println();

       service.delete(1);

       System.out.println();

       service.update(1);

       service.getUserInfo(1);

    }

}

 

 

1.2.2   用XML配置方式进行AOP开发

【切面类,里面无任何注解】

import org.aspectj.lang.ProceedingJoinPoint;

 

publicclass MyAspectByXML {

    publicvoid checkSecurityBefore(){

       System.out.println(" 前置通知MyAspectByXML,安全检查---------");

    }

    publicvoid checkSecurityAfterReturning(){

       System.out.println(" 后置通知MyAspectByXML,安全检查---------");

    }

    publicvoid checkSecurityAfter(){

       System.out.println(" 最终通知MyAspectByXML,安全检查---------");

    }

    publicvoid checkSecurityAfterThrowing(){

       System.out.println(" 例外通知MyAspectByXML,安全检查---------");

    }  

    public Object checkSecurityAround(ProceedingJoinPoint pjp) throws Throwable{

       System.out.println(环绕通知MyAspectByXML进入**************************");

       Object obj = pjp.proceed();

       System.out.println(环绕通知MyAspectByXML结束**************************");

       return obj;

    }

}

 

 

【XML配置文件配置切面,结合前面的MyAspectByXML类】

<?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:context="http://www.springframework.org/schema/context"

       xmlns:aop="http://www.springframework.org/schema/aop"

       xmlns:tx="http://www.springframework.org/schema/tx"

        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd

              http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd

              http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd

              http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">

 

    <!-- 首先启动对@AspectJ注解的支持 -->

    <aop:aspectj-autoproxy/>

   

    <!-- 注解方式的切面 -->

    <bean id="myAspect" class="com.ailk.test.MyAspect"/>

   

    <!-- XML配置文件方式的切面 -->

    <bean id="myAspectByXML" class="com.ailk.test.MyAspectByXML"/>

    <aop:config>

       <aop:aspect id="AspectByXML" ref="myAspectByXML">

           <aop:pointcut id="mycut" expression="execution (* com.ailk.service.impl.UserServiceImpl.add(..))"/>

           <aop:before pointcut-ref="mycut" method="checkSecurityBefore"/>

           <aop:after-returning pointcut-ref="mycut" method="checkSecurityAfterReturning"/>

           <aop:after-throwing pointcut-ref="mycut" method="checkSecurityAfterThrowing"/>

           <aop:after pointcut-ref="mycut" method="checkSecurityAfter"/>

           <aop:around pointcut-ref="mycut" method="checkSecurityAround"/>

       </aop:aspect>

    </aop:config>

    <bean id="userServiceImpl" class="com.ailk.service.impl.UserServiceImpl"/>

</beans>

【备注】

表达式如何写:

Ø  execution (* com.ailk.service.impl.UserServiceImpl.add(..))

表示任意返回值com.ailk.service.impl.UserServiceImpl这个类里面的add方法,该方法输入参数不限;如果add方法修改为*,该类里面的任意方法。

 

Ø  execution (java.lang.String com.ailk.service.impl.UserServiceImpl.add(..))

返回值是String的方法才起效,其它同上

 

Ø  execution (*com.ailk.service.impl.UserServiceImpl.add(java.lang.String,..))

表示该add方法的第一个入参必须是String型,后面的其它参数不管,其它同上。

 

Ø  execution (!void com.ailk.service.impl.UserServiceImpl.add(..))

返回值只要不是void的都处理。

 

Ø  execution (* com.ailk.service.impl..*.add(..))

impl包下面的全部都起效


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值