zl程序教程

您现在的位置是:首页 >  后端

当前栏目

Spring AOP

2023-09-11 14:14:33 时间

1.Spring AOP 中的基本概念

 

a.连接点(Joinpoint

在程序执行过程中某个特定的点,比如某方法调用的时候或者处理异常的时候。在Spring AOP中,一个连接点总是表示一个方法的执行。

 

通俗讲:

层于层之间调用的过程中,目标层中可供调用的方法,就称之为连接点。

b.切入点(Pointcut

匹配连接点的断言。通知和一个切入点表达式关联,并在满足这个切入点的连接点上运行(例如,当执行某个特定名称的方法时)。切入点表达式如何和连接点匹配是AOP的核心:Spring缺省使用AspectJ切入点语法。

通俗讲:

在连接点的基础上 增加上切入规则 选择出需要进行增强的切入点 这些基于切入规则选出来的连接点 就称之为切入点。

c.切面(Aspect

一个关注点的模块化,这个关注点可能会横切多个对象。事务管理是J2EE应用中一个关于横切关注点的很好的例子。在Spring AOP中,切面可以使用基于模式)或者基于@Aspect注解的方式来实现。

通俗讲:

狭义上就是 当spring拦截下切入点后 讲这些切入点 交给 处理类 进行功能的增强,这个处理类就称之为切面。

广义上来讲 讲 spring底层的代理 切入点 和 处理类 加在一起 实现的 对层与层之间调用过程进行增强的机制 称之为切面。

d.通知(Advice

在切面的某个特定的连接点上执行的动作。其中包括了“around”、“before”和“after”等不同类型的通知(通知的类型将在后面部分进行讨论)。许多AOP框架(包括Spring)都是以拦截器做通知模型,并维护一个以连接点为中心的拦截器链。

 通俗讲:

在spring底层的代理拦截下切入点后,讲切入点交由切面类,切面类中就要有处理这些切入点的方法,这些方法就称之为通知(也叫增强 增强方法)。针对于切入点执行的过程,通知还分为不同的类型,分别关注切入点在执行过程中的不同的时机。

e.目标对象(Target Object

被一个或者多个切面所通知的对象。也被称做被通知(advised)对象。 既然Spring AOP是通过运行时代理实现的,这个对象永远是一个被代理(proxied)对象。

 通俗讲:

就是真正希望被访问到的对象。spring底层的动态代理对他进行了代理,具体能不能真的访问到目标对象,或在目标对象真正执行之前和之后是否做一些额外的操作,取决于切面。

 

2.Spring的AOP入门案例

a.导入aop相关开发包

b.创建一个切面类

package cn.tedu.aop;

import org.springframework.stereotype.Component;

@Component
public class FirstAspect {
    public void before(){
    }
}

c.定义通知(增强)

package cn.tedu.aop;

import org.springframework.stereotype.Component;

@Component
public class FirstAspect {
    public void before(){
        System.out.println("before...");
    }
}

d.定义一个连接点

AOPTest.java
package cn.tedu.test;

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

import cn.tedu.service.UserService;

public class AOPTest {
  @Test
    public void test01(){
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserService userService = (UserService) context.getBean("userService");
        userService.addUser(); // 一个连接点
    }
}
UserService.java
package cn.tedu.service;

public interface UserService {
    public void addUser();
    public void updateUser();
    public void deleteUser();
    public void query();
}
UserServiceImple.java
package cn.tedu.service;

import org.springframework.stereotype.Service;

@Service("userService")
public class UserServiceImple implements UserService {

    @Override
    public void addUser() {
        System.out.println("增加用户。。");
    }

    @Override
    public void updateUser() {
        System.out.println("修改用户。。");
    }

    @Override
    public void deleteUser() {
        System.out.println("删除用户。。");
    }

    @Override
    public void query() {
        System.out.println("查询用户。。");
    }
}

e.配置切入点

在MyEclipse中导入aop的schema约束文件,以便于在配置文件中可以提示标签。

在其中配置切入点:

    <aop:config>
        <!-- 配置切入点 -->
        <aop:pointcut expression="within(cn.tedu.service.UserServiceImple)" id="pc01"/>
    </aop:config>

f.定义切面

    <aop:config>
        <!-- 配置切入点 -->
        <aop:pointcut expression="within(cn.tedu.service.UserServiceImple)" id="pc01"/>
        
        <!-- 配置切入面 -->
        <aop:aspect ref="firstAspect">
            <aop:before method="before" pointcut-ref="pc01"/>
        </aop:aspect>
        
    </aop:config>
firstAspect:切面类
before:切面中的方法
pc01:该通知(增强)方法绑定的切入点

g.执行方法,发现切面确实起作用

before...
增加用户。。

3.切入点表达式

a.within表达式

(1)通过类名进行匹配

通过类名进行匹配 粗粒度的切入点表达式

within(包名.类名)

则这个类中的所有的方法都会别表达式识别,成为切入点。

expression="within(cn.tedu.service.UserServiceImple)"

(2)用 * 号匹配符

匹配指定包下所有的类,注意,只匹配当前包,不包括当前包的子孙包。

此处的 * 代表切除该包下的所有类

expression="within(cn.tedu.service.*)"

(3)用 * . * 号匹配符

 匹配包

此处第一个 * 代表一层子目录,第二个 * 代表这个子目录下的所有的类

expression="within(cn.tedu.service.*.*)"

 (4)用 .. * 号匹配符

匹配指定包下及其子孙包下的所有的类

此处的 ..*代表匹配指定包下所有的类

expression="within(cn.tedu.service..*)"

b.execution()表达式

语法:execution(返回值类型 包名.类名.方法名(参数类型,参数类型…))

(1)切出指定包下指定类下指定名称指定参数指定返回值的方法

(2)切出指定包下所有的类中的query方法

要求无参,但返回值类型不限。

(3)切出指定包及其子孙包下所有的类中的query方法

要求无参,但返回值类型不限。

(4)切出指定包及其子孙包下所有的类中的query方法

要求参数为int java.langString类型,但返回值类型不限。

(5)切出指定包及其子孙包下所有的类中的query方法

参数数量及类型不限,返回值类型不限。

(6)切出指定包及其子孙包下所有的类中的任意方法

参数数量及类型不限,返回值类型不限。这种写法等价于within表达式的功能。