Spring——AOP

一、AOP:面向切面编程;

  底层实现:

   1)代理类有接口:使用JDK动态代理;

   2)代理类有接口:可以强制使用CGlib动态代理;

   3)代理类没有接口:使用CGlib动态代理;

二、概念:

  1)连接点(Join point):

    能够被拦截的地方Spring AOP是基于动态代理的,所以是方法拦截的。每个成员方法都可以称之为连接点;

  2)切点(Poincut):

    具体定位的连接点:上面也说了,每个方法都可以称之为连接点,具体定位到某一个方法就成为切点

  3)增强/通知(Advice):

    表示添加到切点的一段逻辑代码,并定位连接点的方位信息

    Spring AOP提供了5种Advice类型:前置、后置、返回、异常、环绕;

  4)织入(Weaving):

    增强/通知添加到目标类的具体连接点上的过程。

  5)引入/引介(Introduction):

    引入/引介允许我们向现有的类添加新方法或属性。是一种特殊的增强!

  6)切面(Aspect):

    切面由切点和增强/通知组成,它既包括了横切逻辑的定义、也包括了连接点的定义。

三、通知类型:实现相应的接口;

通知类型

实现接口

接口方法

xml标签

注释

前置通知

MethodBeforeAdvice

before()

<aop:before>

@Before(value="")

后置通知

AfterReturningAdvice

afterReturning()

<aop:after-returning>

@AfterReturning("")

异常通知

ThrowsAdvice

afterThrowing()  //需要自己实现

<aop:after-throwing>

@AfterThrowing("")

最终通知

/

after()

<aop:after>

@After("")

环绕通知

MethodInterceptor

invoke()

<aop:around>

@Around(value="")

四、XML配置使用示例

  1)导入依赖:

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>aopalliance</groupId>
            <artifactId>aopalliance</artifactId>
            <version>1.0</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.8.7</version>
        </dependency>
pom.xml

  2)配置beans标签约束:

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

xsi:schemaLocation=

       http://www.springframework.org/schema/aop

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

  3)配置通知:

    1、<aop:advisor ></aop:advisor>:一般用于事务管理;

      //切面所在类需要实现接口;

public class LogBefore implements MethodBeforeAdvice {
    @Override
    public void before(Method method, Object[] objects, Object o) throws Throwable {
        System.out.println("前置通知");

    }
}

public class LogAfter implements AfterReturningAdvice {
    @Override
    public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
        System.out.println("后置通知");
    }
}

public class LogException implements ThrowsAdvice {
    public void afterThrowing(Method method, Object[] args, Object target, Exception ex){
        System.out.println("异常通知");
        System.out.println(method.getName());
        System.out.println(ex.getMessage());
    }
}

public class LogAround implements MethodInterceptor {
    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        try {
            System.out.println("前置通知");
            //切点方法执行;
            Object proceed = invocation.proceed();
            System.out.println("后置通知");
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("异常通知");
        } finally {
            System.out.println("最终通知");
        }
        return null;
    }
}
通知类,继承相应接口;
public class UserManager {
    public void addStudent(User user) {
        //System.out.println(3/0);
        System.out.println("增加用户");
    }
}
被增强类
<?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.xsd   http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">

    <bean id="userManager" class="com.qf.aop.UserManager"></bean>
    <bean id="logAfter" class="com.qf.aop.LogAfter"></bean>
    <bean id="logBefore" class="com.qf.aop.LogBefore"></bean>
    <bean id="logException" class="com.qf.aop.LogException"></bean>
    <bean id="logAround" class="com.qf.aop.LogAround"></bean>
    <aop:config>
        <!--配置切入点-->
        <aop:pointcut id="point" expression="execution(* com.qf.aop.UserManager.*(..))"></aop:pointcut>
        <!--配置切入点和切面连接,相当于连接线-->
        <!--<aop:advisor advice-ref="logAfter" pointcut-ref="point"></aop:advisor>-->
        <!--<aop:advisor advice-ref="logBefore" pointcut-ref="point"></aop:advisor>-->
        <!--<aop:advisor advice-ref="logException" pointcut-ref="point"></aop:advisor>-->
        <aop:advisor advice-ref="logAround" pointcut-ref="point"></aop:advisor>
    </aop:config>

</beans>
application-context.xml
public class T {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("application-context.xml");
        UserManager userManager = context.getBean(UserManager.class);
        userManager.addStudent(new User());
    }
}
Test

    2、<aop:aspect ></aop:aspect>:一般用于日志,缓存;

public class Log {
    public void before() {
        System.out.println("前置通知");
    }

    public void afterReturning() {
        System.out.println("后置通知(方法不出现异常)");
    }

    public void afterException() {
        System.out.println("异常通知");
    }

    public void after() {
        System.out.println("最终通知(方法不出现异常)");
    }
}
通知类,无需继承接口;
public class UserManager {
    public void addStudent(User user) {
        //System.out.println(3/0);
        System.out.println("增加用户");
    }
}
被增强类
<?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.xsd   http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">

    <bean id="userManager" class="com.qf.aop.UserManager"></bean>
    <bean id="log" class="com.qf.aop.Log"></bean>
    <aop:config>
        <aop:pointcut id="point" expression="execution(* com.qf.aop.UserManager.*(..))"></aop:pointcut>
        <aop:aspect ref="log">
            <aop:before method="before" pointcut-ref="point"></aop:before>
            <aop:after-returning method="afterReturning" pointcut-ref="point"></aop:after-returning>
            <aop:after method="after" pointcut-ref="point"></aop:after>
            <aop:after-throwing method="afterException" pointcut-ref="point"></aop:after-throwing>
            <aop:around method="afterException" pointcut-ref="point"></aop:around>
        </aop:aspect>
    </aop:config>

</beans>
application-context.xml
public class T {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("application-context.xml");
        UserManager userManager = context.getBean(UserManager.class);
        userManager.addStudent(new User());
    }
}
test

五、execution表达式:

  1)关键字:execution(表达式)

  2)表达式:访问修饰符  返回值  包名.包名.包名...类名.方法名(参数列表)

  3)标准写法:public void com.qf.dao.UserManager.addUser(User user)

  4)访问修饰符可以省略:

    void com.qf.dao.UserManager.addUser(User user)

  5)返回值可以使用通配符,表示任意返回值:

    * com.qf.dao.UserManager.addUser(User user)

  6)包名可以使用通配符,表示任意包。但是有几级包,就需要写几个*.

    * *.*.*.UserManager.addUser(User user)

  7)包名可以使用..表示当前包及其子包:

    * *..UserManager.addUser(User user)

  8)类名和方法名都可以使用*来实现通配:

    * *..*.*(User user)

  9)参数列表:

    1.可以直接写数据类型:

      i.基本类型直接写名称:int

      ii.引用类型写包名.类名的方式:java.lang.String

    2.可以使用通配符表示任意类型,但是必须有参数;

    3.可以使用..表示有无参数均可,有参数可以是任意类型;

  10)全通配写法:

    * *..*.*(..)

  11)实际开发中切入点表达式的通常写法:

    切到业务层实现类下的所有方法:* com.qf.dao.UserManager.*(..)

    <aop:pointcut id="ponitcut" expression="execution(* com.qf.dao.UserManager.*(..))"></aop:pointcut>

 

 

posted @ 2019-08-08 13:38  开拖拉机的拉风少年  阅读(140)  评论(0)    收藏  举报