spring 之AOP
Posted 头发浓密似羊毛
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了spring 之AOP相关的知识,希望对你有一定的参考价值。
第一:什么是AOP?
AOP是面切面编程,是OOP的补充和增强,在程序开发中主要用来解决一些系统层面上的问题。比如,日志事物,权限等待。利用AOP可以对业务逻辑的各个部分进行分离,比如我们在做控制层的时候有时候会碰到需要一些验证等,而使用AOP可以将这些部分与业务逻辑分开,使我们的代码更加专注于业务逻辑的处理,这样不仅降低了逻辑部分之间的耦合性,还增强了代码的可重用性,同时也提高了开发的效率。
第二:AOP的原理是什么?
在我们学习AOP之前都碰到过这样一个问题,那就是我们设计一个项目的时候,往往这个项目的不同部分都是需要验证的,虽然我们可以把相同的代码复制到需要验证的地方,但是这样不仅增加了类之间的耦合性,还使得业务逻辑代码和验证代码混合在一起,不利于代码的维护和管理,而且还增加了大量的重复性代码。而AOP就可以很好的帮助我们解决这个问题,所谓的面向切面编程就是我们利用spring的IOC管理来告诉我们的业务逻辑代码需要插入一个验证信息了,这个时候就是利用AOP直接插入就可以了,而不需要我们在去关心需要什么样的代码这样的问题了。
当我们没有使用AOP的时候,我们就需要在每个需要验证的地方添加代码,而如果使用了AOP,我们只需要写一份代码,然后让IOC管理实现我们在需要的地方插入就可以了。
AOP是基于23种设计模式之一的代理模式来实现的,因为在学习AOP之前,我们需要来学习一下代理模式。
第三:代理模式
代理模式可以分为静态代理模式和动态代理模式;其中动态代理又可以分为jdk动态代理和cglib动态代理
先来学习静态代理:下面给出一个静态代理的小案例
静态代理需要有接口以及该接口的实现类
静态代理中需要用到的包:这里除了spring的IOC需要用到的包外还多了一个aop的包,需要注意
代码如下:
接口代码:
1 public interface SomeService { 2 String doSome(); 3 void say(); 4 }
接口的实现类代码:
1 public class SomeServiceImpl implements SomeService{ 2 @Override 3 public String doSome() { 4 // TODO Auto-generated method stub 5 System.out.println("dosome"); 6 return "halou.."; 7 } 8 @Override 9 public void say() { 10 // TODO Auto-generated method stub 11 System.out.println("say...."); 12 } 13 }
代理的实现方式之一:静态代理类需要自己写代理类
1 public class ProxyFactory implements SomeService{ 2 3 private SomeService target; 4 5 public ProxyFactory(SomeService target) { 6 super(); 7 this.target = target; 8 } 9 10 @Override 11 public String doSome() { 12 System.out.println("---代理1--"); 13 // 执行目标对象的方法 14 String doSome = target.doSome(); 15 System.out.println("---代理2--"); 16 return doSome.toUpperCase(); 17 } 18 19 }
测试类的代码:
1 public class Test { 2 3 public static void main(String[] args) { 4 // 实例化目标对象 5 SomeService target = new SomeServiceImpl(); 6 // 获取代理类 7 SomeService proxy = new ProxyFactory(target ); 8 // 通过代理对象调用方法 9 System.out.println(proxy.doSome()); 10 11 } 12 13 }
测试结果如下:
动态代理之jdk代理模式:
接口代码:
1 public interface SomeService { 2 String doSome(); 3 }
实现类代码:
1 public class SomeServiceImpl implements SomeService { 2 @Override 3 public String doSome() { 4 System.out.println("dosome...."); 5 return "hello.."; 6 } 7 }
测试类以及代理类代码:
1 import java.lang.reflect.InvocationHandler; 2 import java.lang.reflect.Method; 3 import java.lang.reflect.Proxy; 4 import com.sxt.service.SomeService; 5 import com.sxt.serviceimpl.SomeServiceImpl; 6 7 /** 8 * @author ASUS 这是通过jdk动态代理的方式来测试 9 * 10 */ 11 public class Test { 12 public static void main(String[] args) { 13 //实例化目标对象 14 SomeService service=new SomeServiceImpl(); 15 //通过jdk动态代理的方式获取代理对象 16 SomeService proxy=(SomeService) Proxy.newProxyInstance(service.getClass().getClassLoader(),//设置类加载器 17 service.getClass().getInterfaces(),//获取目标对象的所有实现的接口 18 new InvocationHandler() { 19 /** 20 * proxy 代理对象 21 * method 需要执行目标对象的方法 22 * args 目标对象的参数 23 */ 24 @Override 25 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 26 System.out.println("方法执行之前"); 27 String invoke =(String)method.invoke(service, args); 28 System.out.println("方法执行之后"); 29 return invoke.toUpperCase(); 30 } 31 }); 32 System.out.println(proxy.doSome()); 33 } 34 }
运行结果如吓:
动态代理之cglib代理:在cglib代理中需要接口,只需要有对应的目标类就可以了。
目标类代码:
1 package com.sxt.serviceimpl; 2 /** 3 * @author ASUS 4 * cglib的目标类 5 * 6 */ 7 public class SomeServiceImpl { 8 public String doSome() { 9 System.out.println("dosome...."); 10 return "hello.."; 11 } 12 }
测试类代码:
1 import com.sxt.cglib.CglibProxy; 2 import com.sxt.serviceimpl.SomeServiceImpl; 3 4 /** 5 * @author ASUS 这是通过cglib动态代理的方式来测试 6 * 7 */ 8 public class Test { 9 public static void main(String[] args) { 10 //实例化目标对象 11 SomeServiceImpl service=new SomeServiceImpl(); 12 //获取代理类 13 SomeServiceImpl proxy=new CglibProxy(service).createProxy(); 14 System.out.println(proxy.doSome()); 15 } 16 }
cglib代理类代码:
1 import java.lang.reflect.Method; 2 import com.sxt.serviceimpl.SomeServiceImpl; 3 import net.sf.cglib.proxy.Enhancer; 4 import net.sf.cglib.proxy.MethodInterceptor; 5 import net.sf.cglib.proxy.MethodProxy; 6 7 /** 8 * @author ASUS 9 * cglib代理类 10 * 11 */ 12 public class CglibProxy implements MethodInterceptor{ 13 //目标对象 14 private SomeServiceImpl service; 15 public CglibProxy(SomeServiceImpl service) { 16 super(); 17 this.service = service; 18 } 19 /** 20 * 创建代理对象 21 * @return 22 */ 23 public SomeServiceImpl createProxy() { 24 //获取Enhancer对象 25 Enhancer e=new Enhancer(); 26 // 设置父类对象,设置目标对象的类型 27 e.setSuperclass(SomeServiceImpl.class); 28 //设置callback对象,就是this 29 e.setCallback(this); 30 return (SomeServiceImpl)e.create(); 31 } 32 @Override 33 public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { 34 // TODO Auto-generated method stub 35 System.out.println("执行之前"); 36 String invoke =(String) method.invoke(service, args); 37 System.out.println("执行之后"); 38 return invoke.toUpperCase(); 39 } 40 }
注意:在cglib代理中虽然不需要接口,但是要用到一个jar包
我们已经了解了代理模式的原理,现在我们来学习AOP的几种实现方式:
方式一:前置通知,顾名思义就是在目标类的方法执行执行,该前置类的方法会被执行
代码如下:
接口代码:
package com.sxt.service; /** * @author ASUS * 静态代理的公共接口 * */ public interface SomeService { String doSome(); void say(); }
接口的实现类代码:
1 import com.sxt.service.SomeService; 2 /** 3 * @author ASUS 4 * 前置代理接口的实现类 5 * 6 */ 7 public class SomeServiceImpl implements SomeService { 8 @Override 9 public String doSome() { 10 System.out.println("dosome...."); 11 return "hello.."; 12 } 13 @Override 14 public void say() { 15 // TODO Auto-generated method stub 16 System.out.println("ssssss"); 17 } 18 }
前置代理类代码:
1 import java.lang.reflect.Method; 2 import org.springframework.aop.MethodBeforeAdvice; 3 /** 4 * @author ASUS 5 * 6 */ 7 public class MyMethodBeforeAdvice implements MethodBeforeAdvice{ 8 @Override 9 public void before(Method method, Object[] args, Object target) throws Throwable { 10 // TODO Auto-generated method stub 11 System.out.println("前置通知》》》"); 12 } 13 }
测试类代码:
1 import org.springframework.context.ApplicationContext; 2 import org.springframework.context.support.ClassPathXmlApplicationContext; 3 import com.sxt.service.SomeService; 4 5 /** 6 * @author ASUS 测试类 7 * 8 */ 9 public class Test { 10 public static void main(String[] args) { 11 // 获取ApplicationContext对象 加载配置文件 反射+xml解析 12 ApplicationContext ac = new ClassPathXmlApplicationContext("application.xml"); 13 // 从容器中获取代理对象 14 SomeService service = ac.getBean("proxyFactoryBean", SomeService.class); 15 16 String res = service.doSome(); 17 System.out.println(res); 18 System.out.println("-----------------"); 19 service.say(); 20 } 21 }
配置文件代码:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xmlns:p="http://www.springframework.org/schema/p" 5 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> 6 <!-- 注册目标对象 --> 7 <bean class="com.sxt.serviceimpl.SomeServiceImpl" id="someServiceImpl"/> 8 <!-- 注册前置通知 --> 9 <bean class="com.sxt.aspect.MyMethodBeforeAdvice" id="myMethodBeforeAdvice"/> 10 <!-- AOP 配置代理类 --> 11 <bean class="org.springframework.aop.framework.ProxyFactoryBean" id="proxyFactoryBean"> 12 <!-- 配置代理类 --> 13 <property name="target" ref="someServiceImpl"/> 14 <!-- 配置代理类实现的接口 --> 15 <property name="interfaces" value="com.sxt.service.SomeService"/> 16 <!-- 配置通知 --> 17 <property name="interceptorNames"> 18 <list> 19 <!-- 配置前置通知 --> 20 <value>myMethodBeforeAdvice</value> 21 </list> 22 </property> 23 </bean> 24 </beans>
测试结果如下:
需要用到的jar包如下:
AOP实现之后置通知:也就是在目标类的方法执行之后才会执行的
接口代码:
1 package com.sxt.service; 2 /** 3 * @author ASUS 4 * 静态代理的公共接口 5 * 6 */ 7 public interface SomeService { 8 String doSome(); 9 void say(); 10 }
实现类代码:
1 import com.sxt.service.SomeService; 2 /** 3 * @author ASUS 4 * 后置代理接口的实现类 5 * 6 */ 7 public class SomeServiceImpl implements SomeService { 8 @Override 9 public String doSome() { 10 System.out.println("dosome...."); 11 return "hello.."; 12 } 13 @Override 14 public void say() { 15 // TODO Auto-generated method stub 16 System.out.println("ssssss"); 17 } 18 }
后置代理类的代码:
1 package com.sxt.aspect; 2 3 import java.lang.reflect.Method; 4 import org.springframework.aop.AfterReturningAdvice; 5 /** 6 * @author ASUS 7 * 8 */ 9 public class MyAfterReturningAdvice implements AfterReturningAdvice{ 10 @Override 11 public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable { 12 // TODO Auto-generated method stub 13 System.out.println("后置通知"+returnValue); 14 //returnValue=((String)returnValue).toUpperCase(); 15 } 16 }
测试类代码:
1 import org.springframework.context.ApplicationContext; 2 import org.springframework.context.support.ClassPathXmlApplicationContext; 3 import com.sxt.service.SomeService; 4 /** 5 * @author ASUS 测试类 6 * 7 */ 8 public class Test { 9 public static void main(String[] args) { 10 // 获取ApplicationContext对象 加载配置文件 反射+xml解析 11 ApplicationContext ac = new ClassPathXmlApplicationContext("application.xml"); 12 // 从容器中获取代理对象 13 SomeService service = ac.getBean("proxyFactoryBean", SomeService.class); 14 String res = service.doSome(); 15 System.out.println(res); 16 System.out.println("-----------------"); 17 service.say(); 18 } 19 }
配置文件代码:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xmlns:p="http://www.springframework.org/schema/p" 5 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> 6 7 <!-- 注册目标对象 --> 8 <bean class="com.sxt.serviceimpl.SomeServiceImpl" id="someServiceImpl"/> 9 <!-- 注册前置通知 --> 10 <!-- <bean class="com.sxt.aspect.MyMethodBeforeAdvice" id="myMethodBeforeAdvice"/> --> 11 <!-- 注册后置通知 --> 12 <bean class="com.sxt.aspect.MyAfterReturningAdvice" id="myAfterReturningAdvice"/> 13 <!-- AOP 配置代理类 --> 14 <bean class="org.springframework.aop.framework.ProxyFactoryBean" id="proxyFactoryBean"> 15 <!-- 配置代理类 --> 16 <property name="target" ref="someServiceImpl"/> 17 <!-- 配置代理类实现的接口 --> 18 <property name="interfaces" value="com.sxt.service.SomeService"/> 19 <!-- 配置通知 --> 20 <property name="interceptorNames"> 21 <list> 22 <!-- 配置前置通知 --> 23 <!-- <value>myMethodBeforeAdvice</value> --> 24 <!-- 配置后置通知 --> 25 <value>myAfterReturningAdvice</value> 26 </list> 27 </property> 28 </bean> 29 </beans>
测试结果如下:
AOP实现之环绕代理通知:就是在整个目标类方法执行的前后都会执行该环绕代理类的方法
接口代码:
1 public interface SomeService { 2 String doSome(); 3 void say(); 4 }
实现类代码:
1 public class SomeServiceImpl implements SomeService { 2 @Override 3 public String doSome() { 4 System.out.println("dosome...."); 每日一学之认识Spring中的AOP