Spring AOP 实现

一、使用jdk动态代理实现AOP

  • 科普:JDK动态代理是通过java.lang.reflect.Proxy类来实现的,可以调用Proxy类的

    newProxyInstance()方法来创建代理对象。对于使用业务接口的类,Spring默认会使用JDK动态代理来实现AOP。由java jdk提供

  1. 接口类

    public interface UserDao {
    	/**
    	 * 添加用户
    	 */
    	public void addUser();
    	/**
    	 * 删除用户
    	 */
    	public void deleteUser();	
    }
    
  2. 实现类

    public class UserDaoImpl implements UserDao {
    	@Override
    	public void addUser() {
    		// TODO Auto-generated method stub
    		System.out.println("我是添加用户");
    	}
    	@Override
    	public void deleteUser() {
    		// TODO Auto-generated method stub
    		System.out.println("我是删除用户");
    	}
    }
    
  3. 切面类(模拟检查权限,模拟记录日志)

    public class MyAspect {
    	/**
    	 * 检查权限
    	 */
    	public void check() {
    		System.out.println("模拟检查方法");
    	}
    
    	/**
    	 * 记录日志权限
    	 */
    	public void log() {
    		System.out.println("模拟记录日志");
    	}
    }
    
    
  4. jdk代理类

    public class JdkProxy implements InvocationHandler {
    //	声明目标类的接口
    	private UserDao userDao;
    
    	public Object createProxy(UserDao userDao) {
    		this.userDao = userDao;
    //		类加载器
    		ClassLoader classLoader = JdkProxy.class.getClassLoader();
    //		被代理对象实现所有接口
    		Class[] classes = userDao.getClass().getInterfaces();
    //		使用代理类,进行增强,返回的是代理后的对象
    		return Proxy.newProxyInstance(classLoader, classes, this);
    	}
    /** 所有动态代理的方法调用,都会有invoke方法处理
    	proxy:被代理后的对象
        method:将要执行的方法信息
        args执行方法时需要的参数
    */
    	@Override
    	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    		// TODO Auto-generated method stub
    		//声明切面
    		MyAspect myAspect = new MyAspect();
    		myAspect.check();
    		//在目标类调用方法,传入参数
    		Object obj = method.invoke(userDao, args);
    		myAspect.log();
    		return obj;
    	}
    
    }
    
  5. 测试

    public class JdkTest {
    	@Test
    	public void test2() {
    	//实例化jdk代理类
    		JdkProxy jdkProxy = new JdkProxy();
        //创建目标对象
    		UserDao useDao = new UserDaoImpl();
        //从代理类中获取增强后的目标对象
    		UserDao cp = (UserDao) jdkProxy.createProxy(useDao);
    //		执行方法
    		cp.addUser();
    		cp.deleteUser();
    	}
    }
    

二、使用cglib实现Aop

  • 科普:cglib代理是一个高性能开源的代码生成包,利用底层字节码技术,对指定的目标生成一个子类,对子类进行增强,由spring提供
  • 任务描述:创建UserDaoImpl类,不用实现接口。把UserDaoImpl作为目标类,对其中的方法进行增强处理。
  1. 目标类

    public class UserDaoImpl {
    	/**
    	 * 添加用户
    	 */
    	public void addUser() {
    		// TODO Auto-generated method stub
    		System.out.println("我是添加用户");
    	}
    	/**
    	 * 删除用户
    	 */
    	public void deleteUser() {
    		// TODO Auto-generated method stub
    		System.out.println("我是删除用户");
    	}
    }
    
  2. 代理类:

    public class Cglibproxy implements MethodInterceptor {
    	public Object createProxy(Object target) {
    //		创建动态类对象
    		Enhancer enhancer = new Enhancer();
    //		确定需要增强的类,设置其为父类
    		enhancer.setSuperclass(target.getClass());
    //		添加回调函数enhancer
    		enhancer.setCallback(this);
    		return enhancer.create();
    	}
       	//method:拦截的方法,arg2:拦截方法的参数数组,MethodProxy方法的代理对象,用于执行父类的方法
    	@Override
    	public Object intercept(Object proxy, Method arg1, Object[] arg2, MethodProxy methodProxy) throws Throwable {
    		// TODO Auto-generated method stub
    //		创建切面对象
    		MyAspect myAspect = new MyAspect();
    //		前置增强
    		myAspect.check();
    //		目标方法执行
    		Object obj = methodProxy.invokeSuper(proxy, arg2);
    //		后置增强
    		myAspect.log();
    		return obj;
    	}
    }
    
  3. 测试

    public class CglibTest {
    	@Test
    	public void test2() {
    //	创建代理对象
    		Cglibproxy cp = new Cglibproxy();
    //	创建目标对象
    		UserDaoImpl userDaoImpl = new UserDaoImpl();
    //	获取增强后的目标对象
    		UserDao udi = (UserDao) cp.createProxy(userDao);
    //	执行方法
    		udi.addUser();
    		udi.deleteUser();
    
    	}
    }
    

三、spring代理类实现Aop

  • 任务描述:创建配置文件指定代理对象,指定UserDao为代理实现的接口,指定UserDaoImpl为目标类,对其中的方法进行增强处理。
  • 实现思路:创建Spring配置文件,通过定义目标类和切面,然后使用ProxyFactoryBean类定义代理对象。在定义代理对象中,通过子元素指定代理实现的接口,代理的目标对象,需要织入目标类的通知以及代理方式
  1. 切面类

    public class MyAspect implements MethodInterceptor {
    	/**
    	 * 日志信息
    	 */
    	private void log() {
    		// TODO Auto-generated method stub
    		System.out.println("模拟检查日志");
    	}
    	/**
    	 * 模拟检查权限
    	 */
    	private void check() {
    		// TODO Auto-generated method stub
    		System.out.println("模拟检查权限");
    	}
    	@Override
    	public Object invoke(MethodInvocation mi) throws Throwable {
    		// TODO Auto-generated method stub
    		check();
    //		执行目录方法
    		Object object = mi.proceed();
    		log();
    		return object;
    	}
    }
    
  2. spring配置文件

    	<!-- 目标类 -->
    	<bean id="userDao" class="com.ruanyuan.jdk.UserDaoImpl"></bean>
    	<!-- 切面类 -->
    	<bean id="myAspect" class="com.ruanyuan.factorybean.MyAspect"></bean>
    	<!-- 使用spring代理工厂定义一个名称为UserDaoProxy对象 -->
    	<bean id="userDaoProxy"
    		class="org.springframework.aop.framework.ProxyFactoryBean">
    		<!-- 指定实现代理接口 -->
    		<property name="proxyInterfaces"
    			value="com.ruanyuan.jdk.UserDao"></property>
    		<!-- 指定目标对象 -->
    		<property name="target" ref="userDao"></property>
    		<!-- 指定切面,植入环绕通知 -->
    		<property name="interceptorNames" value="myAspect"></property>
    		<property name="proxyTargetClass" value="true"></property>
    	</bean>
    
  3. 测试类

    public class ProxyFactoryBeanTest {
    	@SuppressWarnings("resource")
    	@Test
    	public void test2() {
    //		定义配置路径
    		String path="com/ruanyuan/factorybean/applicationContext.xml";
    //	加载配置路径
    		ApplicationContext context = new ClassPathXmlApplicationContext(path);
    //		获取bean
    		UserDao userDao = (UserDao) context.getBean("userDaoProxy");
    //		执行方法
    		userDao.addUser();
    		userDao.deleteUser();
    	}
    }
    

四、基于xml的声明式AspectJ

  • 任务描述:通过XML文件来定义切面,切入点及通知
  1. 接口类

    public interface UserDao {
    	/**
    	 * 添加用户
    	 */
    	public void addUser();
    	/**
    	 * 删除用户
    	 */
    	public void deleteUser();
    	
    }
    
  2. 实现类

    public class UserDaoImpl implements UserDao{
    	/**
    	 * 添加
    	 */
    	public void addUser() {
    		// TODO Auto-generated method stub
    		System.out.println("我是添加用户");
    	}
    	/**
    	 * 删除
    	 */
    	public void deleteUser() {
    		// TODO Auto-generated method stub
    		System.out.println("我是删除用户");
    	}
    }
    
    
  3. 切面类

    public class MyAspect {
    	/**
    	 * 前置通知
    	 * @param joinPoint
    	 */
    	public void Before(JoinPoint joinPoint) {
    		System.out.println("前置通知,模拟检查权限");
    		System.out.println("目标类是"+joinPoint.getTarget());
    		System.out.println(",被织入增强处理的目标方法"+joinPoint.getSignature().getName());
    		System.out.println("----------------前置分隔----------------------");
    
    	}
    	/**
    	 * 后置返回通知
    	 * @param joinPoint
    	 */
    	public void AfterReturning(JoinPoint joinPoint) {
    		System.out.println("后置通知,模拟记录日志");
    		System.out.println("目标是"+joinPoint.getTarget());
    		System.out.println(",被织入增强处理的目标方法"+joinPoint.getSignature().getName());
    		System.out.println("----------------后置返回分隔----------------------");
    
    	}
    	/**
    	 * 环绕通知
    	 * @param proceedingJoinPoint
    	 * @return
    	 * @throws Throwable
    	 */
    	public Object Around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
    //		环绕开始
    		System.out.println("环绕开始,执行目标方法之前,模拟开启事物");
    		Object obj = proceedingJoinPoint.proceed();
    //		环绕结束
    		System.out.println("环绕结束,模拟事物关闭释放资源");
    		System.out.println("----------------环绕分隔----------------------");
    
    		return obj;
    	}
    	/**
    	 * 异常通知
    	 * @param joinPoint
    	 * @param e
    	 */
    	public void AfterThrowing(JoinPoint joinPoint,Throwable e) {
    		System.out.println("异常通知"+e.getMessage());
    		System.out.println("----------------异常分隔----------------------");
    
    	}
    	/**
    	 * 最终通知
    	 */
    	public void finish() {
    		System.out.println("最终通知,模拟方法结束后的释放资源");
    		System.out.println("----------------最终分隔----------------------");
    
    	}
    }
    
    
  4. 配置文件

    <!-- 目标类 -->
    	<bean id="userDao" class="com.ry.aspectj.UserDaoImpl"></bean>
    	<!-- 切面 -->
    	<bean id="myAspect" class="com.ry.aspectj.MyAspect"></bean>
    	<!-- aop编程 -->
    	<aop:config>
    		<!--配置切面 -->
    		<aop:aspect ref="myAspect">
    			<!-- 配置切入点 -->
    			<aop:pointcut
    				expression="execution(* com.ry.aspectj.*.*(..))"
    				id="myPointCut" />
    			<!-- 前置通知 -->
    			<aop:before method="Before" pointcut-ref="myPointCut" />
    			<!-- 后置通知 -->
    			<aop:after-returning method="AfterReturning"
    				pointcut-ref="myPointCut" returning="returnVal" />
    			<!-- 环绕通知 -->
    			<aop:around method="Around" pointcut-ref="myPointCut" />
    			<!-- 异常通知 -->
    			<aop:after-throwing method="AfterThrowing"
    				pointcut-ref="myPointCut" throwing="e" />
    			<!-- 最终通知 -->
    			<aop:after method="finish" pointcut-ref="myPointCut" />
    		</aop:aspect>
    	</aop:config>
    
    
  5. 测试类

    public class TestXmlAspectj {
    	@Test
    	public void test2() {
    		String path = "com/ruanyuan/aspectj/applicationContext.xml";
    		ApplicationContext context = new ClassPathXmlApplicationContext(path);
    //		从Spring容器获得内容
    		UserDao userDao = (UserDao) context.getBean("userDao");
    //		执行方法
    		userDao.addUser();
    	}
    }
    
    

五、注解实现AOP

  • 通过注解来定义切面,切入点及通知,所有的切面,切入点和通知。
  1. 接口类

    public interface UserDao {
    	/**
    	 * 添加用户
    	 */
    	public void addUser();
    	/**
    	 * 删除用户
    	 */
    	public void deleteUser();
    	
    }
    
  2. 实现类

    @Repository("userDao1")
    public class UserDaoImpl implements UserDao{
    	@Override
    	public void addUser() {
    		// TODO Auto-generated method stub
    		System.out.println("添加用户。。。");
    	}
    
    	@Override
    	public void deleteUser() {
    		// TODO Auto-generated method stub
    		System.out.println("删除用户。。。");
    	}
    }
    
    
  3. 切面类

    @Aspect
    @Component
    public class MyAspect {
    //	定义切入点表达式
    	@Pointcut("execution(* com.ruanyuan.aspectj.annotation.*.*(..))")
    //	使用方法体为空的方法作为切入点
    	private void myPointCut() {
    
    	}
    
    	/**
    	 * 前置通知
    	 * 
    	 * @param joinPoint
    	 */
    	@Before("myPointCut()")
    	public void Before1(JoinPoint joinPoint) {
    		System.out.println("前置通知,模拟检查权限");
    		System.out.println("目标类是" + joinPoint.getTarget());
    		System.out.println(",被织入增强处理的目标方法" + joinPoint.getSignature().getName());
    		System.out.println("----------------前置分隔----------------------");
    	}
    
    	/**
    	 * 后置返回通知
    	 * 
    	 * @param joinPoint
    	 */
    	@After(value = "myPointCut()")
    	public void AfterReturning(JoinPoint joinPoint) {
    		System.out.println("后置通知,模拟记录日志");
    		System.out.println("目标是" + joinPoint.getTarget());
    		System.out.println(",被织入增强处理的目标方法" + joinPoint.getSignature().getName());
    		System.out.println("----------------后置返回分隔----------------------");
    
    	}
    
    	/**
    	 * 环绕通知
    	 * 
    	 * @param proceedingJoinPoint
    	 * @return
    	 * @throws Throwable
    	 */
    	@Around("myPointCut()")
    	public Object Around1(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
    //		环绕开始
    		System.out.println("环绕开始,执行目标方法之前,模拟开启事物");
    		Object obj = proceedingJoinPoint.proceed();
    //		环绕结束
    		System.out.println("环绕结束,模拟事物关闭释放资源");
    		System.out.println("----------------环绕通知分隔----------------------");
    		return obj;
    
    	}
    
    	/**
    	 * 异常通知
    	 * 
    	 * @param joinPoint
    	 * @param e
    	 */
    	@AfterThrowing(value = "myPointCut()", throwing = "e")
    	public void AfterThrowing1(JoinPoint joinPoint, Throwable e) {
    		System.out.println("异常通知" + e.getMessage());
    		System.out.println("----------------异常分隔----------------------");
    
    	}
    
    	/**
    	 * 最终通知
    	 */
    	@After("myPointCut()")
    	public void finish() {
    		System.out.println("最终通知,模拟方法结束后的释放资源");
    		System.out.println("----------------后置分隔----------------------");
    
    	}
    }
    
    
  4. 配置文件

    <?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:context="http://www.springframework.org/schema/context"
    	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
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context.xsd">
           <context:component-scan base-package="com.ruanyuan.aspectj.annotation"/>
           <!-- 基于注解的声明式事物支持 -->
           <aop:aspectj-autoproxy/>
    </beans>   
    
  5. 测试类

    public class AnnotationTest {
    	@Test
    	public void test2() {
    		String path = "com/ruanyuan/aspectj/annotation/applicationContext.xml";
    		ApplicationContext context = new ClassPathXmlApplicationContext(path);
    //		从Spring容器获得内容
    		UserDao userDao = (UserDao) context.getBean("userDao1");
    //		执行方法
    		userDao.addUser();
    	}
    }
    
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值