面向切面编程(一)

xiaoxiao2021-02-28  110

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>

转载请注明原文地址: https://www.6miu.com/read-49733.html

最新回复(0)