AOP 面向切面编程笔记

1、AOP 底层原理及使用动态代理

两种动态代理
第一种有接口情况,使用JDK动态代理
创建接口实现类的代理对象,增强类的方法
第二种没有接口情况,使用CGLIB动态代理
创建当前类子类的代理对象,增强类的方法

2、调用 newProxyInstance 方法

static Object newProxyInstance(ClassLoader loader, 类<?> interfaces, InvocationHandler h)
返回指定接口代理类的实例,该接口将方法调用分派给指定的调用处理程序
方法有三个参数:
第一参数:类加载器
第二参数: 增强方法所在的类, 这个类实现的接口,支持多个接口
第三参数:实现这个接口 InvocationHandler,创建代理对象,写增强的方法

3、编写JDK动态代理代码

可看proxy包

3.1 创建接口,定义方法
3.2 创建接口实现类,实现方法
public class JdkProxy {

    public static void main(String[] args) {
        /**
         * static Object newProxyInstance(ClassLoader loader, 类<?> interfaces, InvocationHandler h)
         * 返回指定接口代理类的实例,该接口将方法调用分派给指定的调用处理程序
         */
        Class[] interfaces = {UserDao.class};
      /*  Proxy.newProxyInstance(JdkProxy.class.getClassLoader(), interfaces, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                return null;
            }
        });*/
        /**
         * 1、可以直接使用匿名内部类
         * 2、可以创建内部类实现InvocationHandler 重写方法
         */
        UserDao userDao = new UserDaoImpl();
        UserDao dao = (UserDao) Proxy.newProxyInstance(JdkProxy.class.getClassLoader(), interfaces, new InnerProxy(userDao));
        int result = dao.add(100, 342);
        System.out.println("result=" + result);
        System.out.println("代理=" + dao);
    }
}
class InnerProxy implements InvocationHandler {
    private Object object;
    public InnerProxy(Object object) {
        this.object = object;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("方法之前执行,方法名=" + method.getName());
        Object invoke = method.invoke(object, args);
        System.out.println("方法之后执行了:" + object);
        return invoke;
    }
}

4、AOP术语

4.1 连接点

类里面可以被增强的方法叫做连接点

4.2 切入点

实际真正被增强的方法,称为切入点

4.3 通知(增强)

1、实际增强的逻辑部分称为通知
2、通知的类型
  2.1、前置通知 @Before
  2.2、后置通知 @After
  2.3、环绕通知 @Around

@Around(value = "execution ( * com.example.demo.aop.aspect.User.run (..))")
public void around(ProceedingJoinPoint joinPoint) throws Throwable {
	System.out.println("环绕之前 ........... ");
	joinPoint.proceed();
	System.out.println("环绕之后 ........... ");
}

  2.4、异常通知 @AfterThrowing
  2.5、最终通知 @AfterReturning finally
无异常时执行顺序: 环绕之前 -> Before -> run -> AfterReturning -> After -> 环绕之后
有异常时执行顺序: 环绕之前 -> Before -> AfterThrowing -> After

4.4 切面

动作,把通知应用到切面点的过程

5、AOP操作

5.1 Spring框架中一般都是基于AspectJ实现AOP操作

1、什么是AspectJ
   AspectJ不是Spring组成部分,独立AOP框架,一般把AspectJ和Spring框架一起使用,进行AOP操作
2、基于AspectJ实现AOP操作
  1、 基于xml配置文件实现
  2、 基于注解方式实现(使用)
3、在项目工程中引入AOP相关依赖
4、切入表达式
切入点表达式的作用: 知道对哪个类里面的哪个方法进行增强

5.2 语法结构:

execution: ( [方法返回类型] [返回路径] [类全路径] [方法名称] ([参数列表]) )
举例一:对 com.example.demo.aop.proxy.UserDao 里面的add 方法进行增强
execution: (* com.example.demo.aop.proxy.UserDao.add(…))
举例二:对 com.example.demo.aop.proxy.UserDao 里面的所有方法进行增强
execution: (* com.example.demo.aop.proxy.UserDao.(…))
举例三:对 com.example.demo.aop.proxy 包里面的所有类,以及类里面的所有方法进行增强
execution: (
com.example.demo.aop.proxy..(…))

6、AOP进行通知的配置

可以看aop/bean1.xml;/aop/aspect

<context:component-scan base-package="com.example.demo.aop.aspect"></context:component-scan>
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
@Component
@Aspect
@Order(3)
public class UserProxy {
    @Pointcut(value = "execution(* com.example.demo.aop.aspect.User.run(..))")
    public void pointCutDemo(){

    }
    @Before(value = "pointCutDemo()")
    public void before(){
        System.out.println("Before ........... ");
    }
    @After(value = "execution(* com.example.demo.aop.aspect.User.run(..))")
    public void after(){
        System.out.println("After ........... ");
    }
    @AfterReturning(value = "execution(* com.example.demo.aop.aspect.User.run(..))")
    public void afterReturning(){
        System.out.println("AfterReturning ........... ");
    }
    @AfterThrowing(value = "execution(* com.example.demo.aop.aspect.User.run(..))")
    public void afterThrowing(){
        System.out.println("AfterThrowing ........... ");
    }
    @Around(value = "execution(* com.example.demo.aop.aspect.User.run(..))")
    public void around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("环绕之前 ........... ");
        joinPoint.proceed();
        System.out.println("环绕之后 ........... ");
    }
}
6.1 在spring配置文件中,开启注解扫描
<context:component-scan base-package="com.example.demo.aop.aspect"></context:component-scan>
6.2 使用注解创建User和UserProxy对象
6.3 在增强类上添加注解@Aspect
@Component 
@Aspect 
public class UserProxy
6.4、在spring配置文件中,开启生成代理对象
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>

7、AOP相同切入点抽取

使用 @Pointcut 进行抽取

@Pointcut(value = "execution(* com.example.demo.aop.aspect.User.run(..))")
public void pointCutDemo(){
}
@Before(value = "pointCutDemo()")
public void before(){
    System.out.println("Before ........... ");
}

8、多个增强类对同一个方法进行增强,设置优先级

8.1 在增强类上面添加注解 @Order(数字类型值),数字值越小,优先级越高

@Order(1); 可看PersonProxy
不加order无异常时执行顺序: 环绕之前 -> Before -> run -> AfterReturning -> After -> 环绕之后
加order无异常时执行顺序:Person before -> 环绕之前 -> Before -> run -> AfterReturning -> After -> 环绕之后

@Component
@Aspect
@Order(1)
public class PersonProxy {
    @Before(value = "execution(* com.example.demo.aop.aspect.User.run(..))")
    public void before() {
        System.out.println("Person before ...");
    }
}

9、Aspectj 配置文件

可以看aop/bean2.xml;/aop/aspectXml

9.1 创建类,在类里面定义方法
9.2 创建增强类,编写增强逻辑

在增强类里面,创建方法,让不同方法代表不同通知类型

9.3 在 Spring 配置文件中配置切入点
    <bean id="book" class="com.example.demo.aop.aspectXml.Book"></bean> 
    <bean id="bookProxy" class="com.example.demo.aop.aspectXml.BookProxy"></bean> 
    <aop:config>
        <aop:pointcut id="pointC" expression="execution(* com.example.demo.aop.aspectXml.Book.buy(..))"/>
        <aop:aspect ref="bookProxy">
            <aop:before method="before" pointcut-ref="pointC"></aop:before>
        </aop:aspect>
    </aop:config>
public class BookProxy {
    public void before(){
        System.out.println("book before ...");
    }
}
public class Book {
    public void buy(){
        System.out.println("buy ......");
    }
}

10、完全注解开发

10.1 创建配置类,不需要配置xml文件开发

@ComponentScan(basePackages = “com.example.demo.aop”)
@EnableAspectJAutoProxy(proxyTargetClass = true) 替代
<aop:aspectj-autoproxy></aop:aspectj-autoproxy> 生成代理对象

@ComponentScan(basePackages = "com.example.demo.aop")
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class AllAnnoAspect {
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值