Aop的使用


AOP基本概念

  • 面向切面编程(方面),利用 AOP 可以对业务逻辑的各个部分进行隔离,从而使得 业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
  • 不修改源代码的方式,为功能添加新功能。

AOP底层原理

  • 有接口时,使用JDK动态代理,创建接口实现类代理对象
  • 无接口时,使用CGLIB动态代理,创建子类的代理对象

JDK动态代理

  • 创建接口类
1
2
3
public interface UserDao {
public int add(int a,int b);
}
  • 实现接口类
1
2
3
4
5
6
public class UserDaoImpl implements UserDao{
@Override
public int add(int a, int b) {
return a+b;
}
}
  • 创建代理对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class JDKProxy {
public static void main(String[] args) {
Class[] interfaces = {UserDao.class};
UserDaoImpl userDao = new UserDaoImpl();
UserDao dao =(UserDao) Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new UserDaoProxy(userDao));
int result = dao.add(1, 2);
System.out.println("result:"+result);
}
}

class UserDaoProxy implements InvocationHandler {
private Object obj;
public UserDaoProxy(Object obj) {
this.obj = obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//方法之前
System.out.println("方法之前执行...."+method.getName()+" :传递的参数..."+ Arrays.toString(args));
//被增强的方法执行
Object res = method.invoke(obj, args);
//方法之后
System.out.println("方法之后执行...."+obj);
return res;
}
}

AOP术语

  • 连接点:可以被增强的类的方法
  • 切入点:实际被增强的类的方法
  • 通知:实际被增强的类的方法的逻辑部分
    • 前置通知:在执行前添加
    • 后置通知:在执行后添加
    • 环绕通知:在执行前和后都添加
    • 异常通知:异常时添加
    • 最终通知:最终添加
  • 切面:把通知应用到切入点的过程

AOP操作

  • 使用AspectJ实现AOP

  • AspectJ是独立框架,和Spring一起使用 ·

  • 引入下列jar包

    • cglib
    • aopalliance
    • aspects
    • aspectjweaver
  • 引入切点表达式

    • execution(* service.UserService.add(..))
    • execution(* service.UserService.*(..))
    • execution(* service.* .*(..))

注解方式实现AOP

实现过程

  • bean.xml
1
2
3
4
5
6
7
8
9
10
11
<?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"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop
http://www.springframework.org/schema/context/spring-aop.xsd">
<context:component-scan base-package="aop"></context:component-scan>
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
  • 创建User类
1
2
3
4
5
6
@Component
public class User {
public void check(){
System.out.println("检查开始");
}
}
  • 创建UserProxy类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
@Component
@Aspect
public class UserProxy {
@Pointcut(value = "execution(* aop.User.check(..))")
public void pointdemo() { }
@Before(value = "pointdemo()")
public void before() {
System.out.println("检查前");
}
@AfterReturning(value = "pointdemo()")
public void afterReturning() {
System.out.println("检查完成");
}
@After(value = "pointdemo()")
public void after() {
System.out.println("检查后");
}
@AfterThrowing(value = "pointdemo()")
public void afterThrowing() {
System.out.println("检查有异常");
}
@Around(value = "pointdemo()")
public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("环绕之前");
proceedingJoinPoint.proceed();
System.out.println("环绕之后");
}
}
  • 测试
1
2
3
4
5
6
@Test
public void test(){
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
User user =context.getBean("user", User.class);
user.check();
}

优先级

  • 使用Order可以设置代理类优先级
  • 数值越小则优先级越高
1
2
3
4
@Component
@Aspect
@Order(1)
public class UserProxy {}

配置方式实现AOP

  • 创建User类
1
2
3
4
5
public class User {
public void check(){
System.out.println("检查开始");
}
}
  • 创建User类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class UserProxy {
public void before() {
System.out.println("检查前");
}
public void afterReturning() {
System.out.println("检查完成");
}
public void after() {
System.out.println("检查后");
}
public void afterThrowing() {
System.out.println("检查有异常");
}
public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("环绕之前");
proceedingJoinPoint.proceed();
System.out.println("环绕之后");
}
}
  • bean.xml
1
2
3
4
5
6
7
8
9
10
11
12
<bean id="user" class="aop.User"></bean>
<bean id="userProxy" class="aop.UserProxy"></bean>
<aop:config>
<aop:pointcut id="p" expression="execution(* aop.User.check())"/>
<aop:aspect ref="userProxy">
<aop:before method="before" pointcut-ref="p"/>
<aop:after-returning method="afterReturning" pointcut-ref="p"/>
<aop:after method="after" pointcut-ref="p"/>
<aop:around method="around" pointcut-ref="p"/>
<aop:after-throwing method="afterThrowing" pointcut-ref="p"/>
</aop:aspect>
</aop:config>