第3章 Spring AOP

3.1 Spring AOP简介

JDK动态代理

         JDK动态代理是通过java.lang.reflect.Proxy 类来实现的,我们可以调用Proxy类的newProxyInstance()方法来创建代理对象。对于使用业务接口的类,Spring默认会使用JDK动态代理来实现AOP。

定义接口与实现类 

package com.itheima.jdk;

public interface UserDao {
    public void addUser();

    public void deleteUser();
}

package com.itheima.jdk;

import org.springframework.stereotype.Repository;

// 目标类
@Repository("userDao")
public class UserDaoImpl implements UserDao {
    public void addUser() {
//		int i = 10/0;
        System.out.println("添加用户");
    }

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

定义切面类 

//在代理中,代理类不仅可以实现必须要实现的业务,同时还可以扩展目标对象的功能
package com.itheima.aspect;

//切面类:可以存在多个通知Advice(即增强的方法)
public class MyAspect {
    public void check_Permissions() {
        System.out.println("模拟检查权限...");
    }

    public void log() {
        System.out.println("模拟记录日志...");
    }
}

 定义代理类

// 三个方法 1.设置代理类要实现的接口setRent 2.返回代理类的实例    3.实现InvocationHandler接口的invoke方法(处理代理实例上的方法调用并返回结果)

//实现InvocationHandler接口生成代理类
// 三个方法 1.设置代理类要实现的接口setRent 2.返回代理类的实例    3.实现InvocationHandler接口的invoke方法(处理代理实例上的方法调用并返回结果)
package com.itheima.jdk;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

import com.itheima.aspect.MyAspect;

/**
 * JDK代理类
 */
public class JdkProxy implements InvocationHandler {
    // 声明目标类接口
    private UserDao userDao;

    // 创建代理方法
    public Object createProxy(UserDao userDao) {
        this.userDao = userDao;
        // 1.类加载器
        ClassLoader classLoader = JdkProxy.class.getClassLoader();
        // 2.被代理对象实现的所有接口
        Class[] clazz = userDao.getClass().getInterfaces();
        // 3.使用代理类,进行增强,返回的是代理后的对象
        return Proxy.newProxyInstance(classLoader, clazz, this);
    }

    /*
     * 所有动态代理类的方法调用,都会交由invoke()方法去处理
     * proxy 被代理后的对象
     * method 将要被执行的方法信息(反射)
     * args 执行方法时需要的参数
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        // 声明切面
        MyAspect myAspect = new MyAspect();
        // 前增强
        myAspect.check_Permissions();
        // 在目标类上调用方法,并传入参数
        Object obj = method.invoke(userDao, args);
        // 后增强
        myAspect.log();
        return obj;
    }
}

 定义测试类 1.实例化带被代理的对象 并用接口接收, 2.实例化代理类  3.执行代理类的方法一,执行代理类的方法二并将返回值转换为接口类型 ,4.执行接口相关的方法。

package com.itheima.jdk;

public class JdkTest {
    public static void main(String[] args) {
        // 创建代理对象
        JdkProxy jdkProxy = new JdkProxy();
        // 创建目标对象
        UserDao userDao = new UserDaoImpl();
        // 从代理对象中获取增强后的目标对象
        UserDao userDao1 = (UserDao) jdkProxy.createProxy(userDao);
        // 执行方法
        userDao1.addUser();
        userDao1.deleteUser();
    }
}

ProxyFactoryBean实现代理

xml 需要配置目标类,自定义的切面类(需要实现MethodInterceptor)、使用ProxyFactoryBean 并设置三个参数

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans 
	http://www.springframework.org/schema/beans/spring-beans-4.3.xsd">
	<!-- 1 目标类 -->
	<bean id="userDao" class="com.itheima.jdk.UserDaoImpl" />
	<!-- 2 切面类 -->
	<bean id="myAspect" class="com.itheima.factorybean.MyAspect" />
	<!-- 3 使用Spring代理工厂定义一个名称为userDaoProxy的代理对象 -->
	<bean id="userDaoProxy" 
            class="org.springframework.aop.framework.ProxyFactoryBean">
		<!-- 3.1 指定代理实现的接口-->
		<property name="proxyInterfaces" 
                      value="com.itheima.jdk.UserDao" />
		<!-- 3.2 指定目标对象 -->
		<property name="target" ref="userDao" />
		<!-- 3.3 指定切面,织入环绕通知 -->
		<property name="interceptorNames" value="myAspect" />
		<!-- 3.4 指定代理方式,true:使用cglib,false(默认):使用jdk动态代理 -->
		<property name="proxyTargetClass" value="true" />
	</bean>
</beans>

省略UserDaoImpl

切面类需要实现MethodInterceptor

package com.itheima.factorybean;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

// 切面类需要实现MethodInterceptor接口的invoke()方法
public class MyAspect implements MethodInterceptor {
    @Override
    public Object invoke(MethodInvocation mi) throws Throwable {
        check_Permissions();
        // 执行目标方法
        // 继续到链中的下一个拦截器 Joinpoint.proceed()
        Object obj = mi.proceed();
        log();
        return obj;
    }

    public void check_Permissions() {
        System.out.println("模拟检查权限...");
    }

    public void log() {
        System.out.println("模拟记录日志...");
    }
}

测试方法

// 测试类
public class ProxyFactoryBeanTest {
    public static void main(String args[]) {
        String xmlPath = "com/itheima/factorybean/applicationContext.xml";
        ApplicationContext applicationContext =
                new ClassPathXmlApplicationContext(xmlPath);
        // 从Spring容器获得内容
        UserDao userDao =
                (UserDao) applicationContext.getBean("userDaoProxy");
        // 执行方法
        userDao.addUser();
        userDao.deleteUser();
    }
}

基于注解的声明式AspectJ

@Aspect 切面注解使用 - 秃了也变强了 - 博客园 (cnblogs.com)icon-default.png?t=M4ADhttps://www.cnblogs.com/dd1992dd/p/12851620.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值