面向切面编程(一)

spring AOP的核心设计思想是代理模式。

 spring AOP的主要功能是日志记录、性能统计、安全控制、事务处理、异常处理等等。spring AOP 可以将日志记录、性能统计、安全控制、事务处理、异常处理等代码从业务逻辑代码中划分出来,通过对这些行为的分离,我们希望可以将它们独立到非指导业务逻辑的方法中,进而改变这些行为的时候不影响业务逻辑的代码。
      

一、AOP术语介绍:(其中连接点、切入点、切面比较重要)

       1.通知(Advice): 通知定义了切面是什么以及何时使用。描述了切面要完成的工作和何时需要执行这个工作。
       2.连接点(Joinpoint):程序能够应用通知的一个“时机”,这些“时机”就是连接点,例如方法被调用时、异常被抛出时等等。
       3.切入点(Pointcut):通知定义了切面要发生的“故事”和时间,那么切入点就定义了“故事”发生的地点,例如某个类或方法的名称, spring中允许我们方便的用正则表达式来指定
       4.切面(Aspect):
通知和切入点共同组成了切面:时间、地点和要发生的“故事”
       
5.引入(Introduction): 引入允许我们向现有的类添加新的方法和属性(Spring提供了一个方法注入的功能)
       
6.目标(Target): 即被通知的对象,如果没有AOP,那么它的逻辑将要交叉别的事务逻辑,有了AOP之后它可以只关注自己要做的事(AOP让他做爱做的事)
       
7.代理(proxy): 应用通知的对象,详细内容参见设计模式里面的代理模式
       
8.织入(Weaving): 把切面应用到目标对象来创建新的代理对象的过程,织入一般发生在如下几个时机:
(1)编译时:当一个类文件被编译时进行织入,这需要特殊的编译器才可以做的到,例如AspectJ的织入编译器
(2)类加载时:使用特殊的ClassLoader在目标类被加载到程序之前增强类的字节代码
(3)运行时:切面在运行的某个时刻被织入,SpringAOP就是以这种方式织入切面的,原理应该是使用了JDK的动态代理技术


二、前置通知

      所谓前置通知就是在用户对系统进行操作之前打印日志,比如登录之前会检测登录用户。前置通知实现的是MethodBeforeAdvice接口。

      示例代码:

      前置通知实现类CheckUser.java:     

package com.mfc.advice;

import java.lang.reflect.Method;

import org.springframework.aop.MethodBeforeAdvice;

public class CheckUser implements MethodBeforeAdvice {

	public void before(Method method, Object[] objects, Object object) throws Throwable {
		String username = (String) objects[0]; 
		System.out.println("正在对【"+username+"】用户进行身份检测...");
	}
}

模拟用户登录接口UserLogin.java:

public interface UserLogin {
	public void login(String username);
}

实现用户登录接口UserLoginImpl.java:

public class UserLoginImpl implements UserLogin {

	public void login(String username) {
		System.out.println(username+"正在登陆系统后台...");
	}
}

测试类BeforeAdviceTest.java:

package com.mfc.test;

import javax.jws.soap.SOAPBinding.Use;

import org.springframework.aop.BeforeAdvice;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.mfc.advice.CheckUser;
import com.mfc.impl.UserLoginImpl;
import com.mfc.interfaces.UserLogin;

public class BeforeAdviceTest {
	 public static void main(String[] args) {
		 //方法一:直接在调用时生成代理
		/*UserLogin login = new UserLoginImpl();  //具体的登录用户
		BeforeAdvice advice = new CheckUser();  //前置通知
		ProxyFactory factory = new ProxyFactory();  //spring代理工厂
		factory.setTarget(login);  //设置代理目标
		factory.addAdvice(advice);  //为代理目标添加前置通知
		UserLogin proxy = (UserLogin) factory.getProxy();  //生成代理实例
		proxy.login("孟凡诚");  //调用登陆方法
*/		
		//方法二:通过spring配置文件配置来声明代理
		 ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
		UserLogin login=(UserLogin) applicationContext.getBean("userlogin");
		login.login("孟凡诚");
	}
}

spring配置文件:

<bean id="checkUser" class="com.mfc.advice.CheckUser"></bean>
	<bean id="target" class="com.mfc.impl.UserLoginImpl"></bean> 
	<!-- 使用代理工厂配置一个代理 -->
	<bean id="userlogin" class="org.springframework.aop.framework.ProxyFactoryBean">
		<!-- 指定代理接口,如果是多个接口,就使用list元素指定 -->
		<property name="proxyInterfaces" value="com.mfc.interfaces.UserLogin"></property>
		<!-- 指定通知 -->
		<property name="interceptorNames" value="checkUser"></property>
		<!-- 指定目标对象 -->
		<property name="target" ref="target"></property>
	</bean>

三、后置通知:

        所谓后置通知,就是在用户执行某一操作之后,进行日志输出。后置通知实现的是AfterReturningAdvice接口。

后置通知实现类:

public class WelcomeUser implements AfterReturningAdvice {
	public void afterReturning(Object object, Method method, Object[] objects, Object target) throws Throwable {
		String username = (String) objects[0];
		System.out.println("欢迎您:"+username+"登陆成功!");
	}
}

配置文件:

<!-- 定义通知类 -->
	<bean id="welcomeUser" class="com.mfc.advice.WelcomeUser"></bean>
	<!-- 定义目标类 -->
	<bean id="target" class="com.mfc.impl.UserLoginImpl"></bean>
	<!-- 使用spring代理工厂配置一个代理 -->
	<bean id="proxyFactoryBean" class="org.springframework.aop.framework.ProxyFactoryBean">
		<!-- 指定代理接口,如果是多个接口,就使用list元素指定 -->
		<property name="proxyInterfaces" value="com.mfc.interfaces.UserLogin"></property>
		<!-- 指定通知 -->
		<property name="interceptorNames" value="welcomeUser"></property>
		<!-- 指定目标对象 -->
		<property name="target" ref="target"></property>
	</bean>
测试类:

public class AfterAdviceTest {
	public static void main(String[] args) {
		ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
		UserLogin login = (UserLogin) applicationContext.getBean("proxyFactoryBean");
		login.login("孟凡诚");
	}
}	

模拟用户登录的类同前置通知。


四、环绕通知:

        所谓的环绕通知,就是在用户对系统进行操作前后都会输出日志。实现MethodInterceptor接口。MethodInterceptor是AOP联盟接口。

环绕通知实现类:

package com.mfc.advice;

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

public class CheckUserWelcome implements MethodInterceptor {

	public Object invoke(MethodInvocation invocation) throws Throwable {
		Object[] objs = invocation.getArguments();  //目标方法入参
		String username = (String) objs[0];			//获取用户名
		//在目标方法执行前调用
		System.out.println("正在对【"+username+"】用户进行身份检测...");
		//通过反射调用执行方法
		Object object=invocation.proceed();
		//在目标方法执行后调用
		System.out.println("欢迎您:"+username+",登录成功!");
		return object;
	}
}

spring配置:

<bean id="checkUserWelcome" class="com.mfc.advice.CheckUserWelcome"></bean>
	<bean id="target" class="com.mfc.impl.UserLoginImpl"></bean>
	<bean id="proxyFactoryBean" class="org.springframework.aop.framework.ProxyFactoryBean">
		<property name="proxyInterfaces" value="com.mfc.interfaces.UserLogin"></property>
		<property name="interceptorNames" value="checkUserWelcome"></property>
		<property name="target" ref="target"></property>
	</bean>

测试类:

public class BeforeAdviceTest {
	 public static void main(String[] args) {

		 ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
		UserLogin login=(UserLogin) applicationContext.getBean("proxyFactoryBean");
		login.login("孟凡诚");
	}
}

五、异常通知:

       在目标方法抛出异常时调用。实现ThrowsAdvice接口。

用户登录的接口:

public interface UserLogin {
	public void login(String username);
}
实现用户登录接口的类:

public class UserLoginImpl implements UserLogin {
	public void login(String username) {
		if(username.equals("孟凡诚")){
			System.out.println(username+"正在登陆系统后台...");
		}else{
			throw new RuntimeException("输入的 用户名不正确!");
		}
	}
}

异常通知实现类:

public class CheckUser implements ThrowsAdvice {
	public void afterThrowing (Method method , Object[] objs , Object target , Exception exception){
		System.out.println("Method:"+method.getName()+"抛出异常:"+exception.getMessage());
	}
}

spring配置文件:

<bean id="checkUser" class="com.mfc.advice.CheckUser"></bean>
	<bean id="target" class="com.mfc.impl.UserLoginImpl"></bean>
	<bean id="proxyFactoryBean" class="org.springframework.aop.framework.ProxyFactoryBean">
		<property name="proxyInterfaces" value="com.mfc.interfaces.UserLogin"></property>
		<property name="interceptorNames" value="checkUser"></property>
		<property name="target" ref="target"></property>
	</bean>



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值