Spring AOP(二)-AOP的实现

一、AOP的一些专业术语

* 切面(Aspect) : 横切关注点。就是交叉在各个业务逻辑中的系统服务(被模块化),类似于安全验证、事务处理、日志记录都可以理解为切面。

* 织入(weaving) : 就是将切面代码插入到目标对象某个方法的过程,相当于我们在jdk动态代理里面的 invocationHandler接口方法的内容 。

* 连接点(JointPoint) : 理论上可能被切面织入的所有方法 ,比如addUser(), searchUser()的方法前、方法后或抛异常后等等。通常所有方法都可以被称为连接点。

* 切入点(PointCut) : 就是实际上被切面织入的方法。

* 目标对象(target) : 就是切入点和连接点所属的类 UserDaoImpl,被通知的对象。

* 通知(Advice) : 就是切面的实现,切面必须要完成的工作。

* 代理(Proxy) : 向目标对象应用通知之后创建的对象。

* 顾问(Advisor) : 其实就是通知的一个封装和延伸,可以将通知以更为复杂的方式织入到某些方法中
将切面织入到目标对象的连接点方法,使连接点成为切入点

AOP : 是不是就是 把通知织入到连接点的过程

二、spring AOP 的实现

AOP开发规范:
AOP联盟为Advice定义了:org.aoplliance.aop.interface.Advice
spring AOP实现了AOP联盟的规范
传统spring提供的五类Advice
前置通知org.springframework.aop.MethodBeforeAdvice
* 在目标方法执行前实施
后置通知 org.springframework.aop.AfterReturningAdvice
* 在目标方法执行后实施
环绕通知 org.aopalliance.intercept.MethodInterceptor
* 在目标方法执行前后实施
异常抛出通知 org.springframework.aop.ThrowsAdvice
* 在方法抛出异常后实施
引介通知 org.springframework.aop.IntroductionInterceptor 了解
* 在目标类中添加一些新的方法和属性

三、案列解析

首先借口和实现类是前面已经写了
首先创建一个IUserDao接口,编写addUser和serchUser方法
package com.dqsy.spring.proxy;

public interface IUserDao {
	
	public void addUser();
	public void serchUser();
}
实现这个接口:
package com.dqsy.spring.proxy.impl;

import com.dqsy.spring.proxy.IUserDao;

public class IUserDaoImpl implements IUserDao {

	@Override
	public void addUser() {
		// TODO Auto-generated method stub
		/**
		 * 业务逻辑服务
		 */
		/**
		 * 首先进行权限的判断
		 */
		
		//System.out.println("判断权限....");
		System.out.println("添加方法....");
		/**
		 * 编写日志
		 * 
		 */
		//System.out.println("编写日志");
		int a = 1/0;//后面的异常通知会用到
	}

	@Override
	public void serchUser() {
		// TODO Auto-generated method stub
		System.out.println("寻找方法....");
	}

}
编写前置通知
package com.dqsy.spring.proxy;

import java.lang.reflect.Method;

import org.springframework.aop.MethodBeforeAdvice;

public class MyBeforeAdvice implements MethodBeforeAdvice {

	@Override
	public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable {
		// TODO Auto-generated method stub
		System.out.println("前置通知  ....在方法执行前运行");
	}

}
然后编写applicationContext.xml
	<!-- 配置IUserDaoImpl -->
	<bean id="userDao" class="com.dqsy.spring.proxy.impl.IUserDaoImpl"></bean>
	<!-- 注册前置的通知,切面的实现 -->
	<bean id="beforeAdvice" class="com.dqsy.spring.proxy.MyBeforeAdvice"></bean>
	<!-- 注册前置通知代理生成器, 注入目标接口,目标类,通知 -->
	<bean id="myBeforeProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
		<property name="target" ref="userDao"></property>
		<property name="interfaces" value="com.dqsy.spring.proxy.IUserDao"></property>
		<property name="interceptorNames" value="beforeAdvice"></property>
	</bean>
编写测试文件
public class AdviceTest {
	private ApplicationContext ctx=null;
	@Before
	public void init(){
		ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
	}
	//前置通知
	@Test
	public void beforText(){
		IUserDao userDao = (IUserDao) ctx.getBean("myBeforeProxy");//代理对象
		userDao.addUser();
		
	}
结果:

后置通知:
编写MyAfterAdvice类
package com.dqsy.spring.advice;

import java.lang.reflect.Method;

import org.springframework.aop.AfterReturningAdvice;

public class MyAfterAdvice implements AfterReturningAdvice {

	@Override
	public void afterReturning(Object retuenValue, Method paramMethod, Object[] paramArrayObject, Object targert) throws Throwable {
		// TODO Auto-generated method stub
		System.out.println("后置通知...在方法执行后运行");

	}

}
测试类及结果:
//后置通知
	@Test
	public void afterText(){
		IUserDao userDao = (IUserDao) ctx.getBean("myAfterProxy");//代理对象
		userDao.addUser();
		
	}

环绕方法MyAroundAdvice类:
package com.dqsy.spring.advice;

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

public class MyAroundAdvice implements MethodInterceptor {

	@Override
	public Object invoke(MethodInvocation invocation) throws Throwable {
		// TODO Auto-generated method stub
		System.out.println("环绕通知...在方法前执行");
		Object result = invocation.proceed();
		System.out.println("环绕通知...在方法后执行");
		result = false;
		return result;
	}

}
测试方法和结果:
package com.dqsy.spring.advice;

import org.springframework.aop.ThrowsAdvice;

public class MyThrowingAdvice implements ThrowsAdvice {
	public void afterThrowing(Exception e){
		System.out.println("发生异常"+e.toString());
	}
}

测试及结果:
	//异常通知
	@Test
	public void throwText(){
		IUserDao userDao = (IUserDao) ctx.getBean("myAroundProxy");//代理对象
		userDao.addUser();
		
	}

注意事项:
在编程时,应该使用 ProxyFactoryBean 创建后代理对象(UserDAOProxy ), 不要引入原来Bean (UserDAO)。

小结:
一个代理对象只能代理一个bean,意味着在实际应用中要定义多个代理(通过默认advisor自动代理生成器来解决。
从容器中获取对象是通过代理的bean的id,而不是我们在容器里面定义的目标对象的id(通过默认advisor自动代理生成器来解决)。
通知只能切入到目标类的所有方法,不能指定某些方法(通过顾问对通知的封装实现)。
























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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

奋斗的小巍

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值