spring之AOP
来源:互联网 发布:js原型继承原理 编辑:程序博客网 时间:2024/04/29 22:16
什么是AOP
Aspect Oriented Programing面向切面编程。利用AOP的技术我们可以轻松消除分散在各个模块逻辑代码中的重复代码,可以对我们指定的方法增强,代理等等
aop术语
- 连接点Joinpoint
程序执行的某个特定的位置,某个方法调用前,某个方法调用后,方法抛出异常后等等 - 切点pointcut
- 增强advice
- 目标Target
需要被增强的目标类 - 引入 introduction为某个类添加属性或者方法,或者继承某个类
- 织入weaving
- 代理proxy
切面aspect
springAop代理机制
jdk自带的动态代理
jdk的动态代理主要用到了Java.lang.reflect包下面的Proxy和InvocationHandler
代理类PlayGameProxy .java
public class PlayGameProxy implements InvocationHandler { static Logger logger = Logger.getLogger(PlayGameProxy.class); Object traget; public PlayGameProxy(Object playGameInterface) { this.traget = playGameInterface; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { logger.info("打开电脑噢"); Object object = method.invoke(traget, args); logger.info("关闭电脑"); return object; }}
调用类
public class NormalProxyTest { @Test public void test() { PlayGameInterface pg = new StartPlayGame(); PlayGameProxy pgProxy = new PlayGameProxy(pg); // Proxy.newProxyInstance()最主要是这个方法 PlayGameInterface PlayGaemProxy = (PlayGameInterface) Proxy.newProxyInstance(pg.getClass().getClassLoader(), pg.getClass().getInterfaces(), pgProxy); PlayGaemProxy.palyGame(); PlayGaemProxy.palyGame2(); }}
- cglib的动态代理,因为jdk的代理技术必须要有接口类,如果某些类没有接口,就无法实现动态代理了,所以这时候cglib就出场了采用了字节码技术。主要用到了Enhancer类去增强
CglibProxy.java
@Slf4jpublic class CglibProxy implements MethodInterceptor { Enhancer enhancer = new Enhancer(); public Object getProxy(Class clazz) { enhancer.setSuperclass(clazz);// 设置子类需要创建的类 enhancer.setCallback(this); return enhancer.create();// 创建子类实例 } public Object intercept(Object obj, Method arg1, Object[] args, MethodProxy proxy) throws Throwable { log.info("【1】打开电脑噢"); Object result = proxy.invokeSuper(obj, args); log.info("【3】关闭电脑"); return result; }}
测试类
@Test public void test() { CglibProxy cglibProxy = new CglibProxy(); StartPlayGame startPlayGame = (StartPlayGame) cglibProxy.getProxy(StartPlayGame.class); startPlayGame.palyGame(); startPlayGame.palyGame2(); }
输出结果:
2015-06-30 15:02:43,785 INFO [main] (CglibProxy.java:27) - 【1】打开电脑噢
开始玩游戏了噢
2015-06-30 15:02:43,807 INFO [main] (CglibProxy.java:29) - 【3】关闭电脑
2015-06-30 15:02:43,807 INFO [main] (CglibProxy.java:27) - 【1】打开电脑噢
开始玩游戏了噢22222
2015-06-30 15:02:43,807 INFO [main] (CglibProxy.java:29) - 【3】关闭电脑
缺点:
如果我们只想给某个类(StartPlayGame)的某个方法(palyGame)加上代理,其他的方法不加代理。使用动态代理是做不到的,动态代理会给目标类的所有方法都加上增强。
如果我们代理一个类就要专门为这个类创建代理过程,编写相关代码,无法做到通用。
所以后面才引入了切点切面的概念!
Aop联盟
创建增强类Advice MethodBeforeAdvice(前置增强)、MethodInterceptor(拦截)、AfterReturningAdvice(后置增强)
其实实现效果就是相当于动态代理技术里面 invoke或者intercept方法,在调用真正方法之前,进行的操作。
通过代码配置增强
@Slf4jpublic class PlayGameBeforAdvice implements MethodBeforeAdvice { public void before(Method method, Object[] args, Object target) throws Throwable { log.info("【1】方法执行之前"); }}public class PlayGameAfterAdvice implements AfterReturningAdvice { public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable { log.info("【3】方法执行之后"); }}public class PlayGameInterceptor implements MethodInterceptor { public Object invoke(MethodInvocation invocation) throws Throwable { log.info("【1】环绕增强之前"); invocation.proceed();// 调用反射执行方法 log.info("【3】环绕增强之后"); return null; }}
测试
private void testByMethod() { // 测试前置增强 PlayGameBeforAdvice pba = new PlayGameBeforAdvice(); excuteAdviceByParam(pba); // 测试后置增强 PlayGameAfterAdvice paa = new PlayGameAfterAdvice(); excuteAdviceByParam(paa); // 测试环绕增强 PlayGameInterceptor pgi = new PlayGameInterceptor(); excuteAdviceByParam(pgi); } public void excuteAdviceByParam(Advice advice) { try { PlayGame target = new PlayGameImp(); // spring提供的代理工厂 ProxyFactory proxy = new ProxyFactory(); // 设置代理的接口 proxy.setInterfaces(target.getClass().getInterfaces()); // 设置代理目标 proxy.setTarget(target); // 为代理目标添加增强 proxy.addAdvice(advice); // 强制以cglib形式代理 对于单例模式来说第一次创建比较慢,后来就好。 proxy.setOptimize(true); // 生成代理类 PlayGame play = (PlayGame) proxy.getProxy(); play.playLOL(); } catch (Exception e) { log.error("测试aop增强失败!:" + e.getLocalizedMessage()); } }
通过spring配置增强
<?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:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"> <!-- 前置增强,后置增强,环绕增强 --> <bean id="target" class="com.team.gaoguangjin.springinaction.springAop.PlayGameImp" /> <bean id="playGameAfterAdvice" class="com.team.gaoguangjin.springinaction.springAop.PlayGameAfterAdvice" /> <bean id="playGameBeforAdvice" class="com.team.gaoguangjin.springinaction.springAop.PlayGameBeforAdvice" /> <bean id="playGameInterceptor" class="com.team.gaoguangjin.springinaction.springAop.PlayGameInterceptor" /> <!-- xml配置aop的关系 --> <bean id="play" class="org.springframework.aop.framework.ProxyFactoryBean" p:proxyInterfaces="com.team.gaoguangjin.springinaction.springAop.PlayGame" p:interceptorNames="playGameBeforAdvice" p:target-ref="target" p:proxyTargetClass="true" p:singleton="true" /> </beans>
测试代码
private void testAopXml() { try { ApplicationContext ac = new ClassPathXmlApplicationContext("com/team/gaoguangjin/springinaction/springAop/beans.xml"); PlayGame play = (PlayGame) ac.getBean("play"); play.playLOL(); } catch (Exception e) { log.error("测试xml aop增强失败!:" + e.getLocalizedMessage()); } }
基于@Aspectj和schema配置的AOP
- aspectj
基于aspect的代码配置aop
AspectDemo.java 切面类
@Aspect@Slf4jpublic class AspectDemo { @Before("execution(* playLOL(..))") public void beging() { log.info("【1】 玩游戏之前需要【打开】电脑 通过方法方式"); } @After("execution(* playLOL(..))") public void end() { log.info("【3】 不想玩游戏睡觉了需要【关闭】电脑 通过方法方式"); } @Before("execution(* playCs(..))") public void beging1() { log.info("【1】 玩游戏之前需要【打开】电脑 通过xml方式"); } @After("execution(* playCs(..))") public void end2() { log.info("【3】 不想玩游戏睡觉了需要【关闭】电脑 通过xml方式"); } // 拦截所有带了注解的方法 @Before("@annotation(com.team.gaoguangjin.springinaction.annoation.JdkAnnoation)") public void annationBegin() { log.info("【1】 注解方法运行之前"); } @After("@annotation(com.team.gaoguangjin.springinaction.annoation.JdkAnnoation)") public void annationEnd() { log.info("【3】 注解方法之后"); }}
代码调用,当playLOL方法被调用时候,会触发@Before和@After
execution里面是条件
private void getFromMethod() { PlayGame target = new PlayGameImp(); // 定义 AspectJProxyFactory 而不是ProxyFactory AspectJProxyFactory aspectFactory = new AspectJProxyFactory(); // 先要setTarget 然后再添加aspect切面 aspectFactory.setTarget(target); // 添加切面类 aspectFactory.addAspect(AspectDemo.class); // 生成切面的代理对象 PlayGame proxy = aspectFactory.getProxy(); proxy.playLOL(); }
基于aspect的xml配置aop
<?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:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"> <!--【1】与【2】效果类似,用其中一个就可以了 --> <!-- 【1】基于切面的驱动器 --> <aop:aspectj-autoproxy /> <!--http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"> 【2】自动代理创建器, <bean class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator"/> --> <bean id="playGame" class="com.team.gaoguangjin.springinaction.aspectAop.PlayGameImp" /> <bean id="asepectDemo" class="com.team.gaoguangjin.springinaction.aspectAop.AspectDemo" /></beans>
调用测试,因为<aop:aspectj-autoproxy />
会自动扫描注解需要代理的对象
private void geFromXml() { try { ApplicationContext ac = new ClassPathXmlApplicationContext("com/team/gaoguangjin/springinaction/aspectAop/beans.xml"); PlayGame play = (PlayGame) ac.getBean("playGame"); play.playCs(); } catch (Exception e) { log.error("通过xml方式得到aspect注解的aop失败!" + e.getLocalizedMessage()); } }
Schema
基于schemd的 aspect配置增强类切面AdviceMethods .java
public class AdviceMethods { public void preGreeting(String name) { System.out.print("所有方法都会触发!--参数为:"); System.out.println(name); } // 后置增强对应方法 public void afterReturning(String retVal) { System.out.println("----afterReturning()----"); System.out.println("returnValue:" + retVal); System.out.println("----afterReturning()----"); } // 环绕增强对应方法 public void aroundMethod(ProceedingJoinPoint pjp) { System.out.println("----aroundMethod()----"); System.out.println("args[0]:" + pjp.getArgs()[0]); System.out.println("----aroundMethod()----"); } // 抛出异常增强 public void afterThrowingMethod(IllegalArgumentException iae) { System.out.println("----afterThrowingMethod()----"); System.out.println("exception msg:" + iae.getMessage()); System.out.println("----afterThrowingMethod()----"); } // final增强 public void afterMethod() { System.out.println("----afterMethod()----"); } // ------------绑定连接点参数----------// public void bindParams(int num, String name) { System.out.println("----bindParams()----"); System.out.println("name:" + name); System.out.println("num:" + num); System.out.println("----bindParams()----"); }}
<?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:aop="http://www.springframework.org/schema/aop" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"> <bean id="adviceMethods" class="com.team.gaoguangjin.springinaction.schemaAspectAop.AdviceMethods" /> <aop:config proxy-target-class="true"> <!--可以配置多个 aop:aspect --> <aop:aspect ref="adviceMethods"> <!-- args(name) 这个name属性为 public void preGreeting(String name)--> <aop:pointcut expression="target(com.team.gaoguangjin.springinaction.schemaAspectAop.PlayGameImp) and args(name)" id="playGamePointcut"/> <!--1PlayGameImp类的所有方法运行之前 都会触发这个条件 <aop:before method="preGreeting" pointcut="target(com.team.gaoguangjin.springinaction.schemaAspectAop.PlayGameImp) and args(name)" arg-names="name" /> --> <!--2PlayGameImp类的所有方法运行之前 都会触发这个条件 1和2一样,只是用到了pointcut--> <aop:before method="preGreeting" pointcut-ref="playGamePointcut"/> <!--某个类的任何方法运行之后都会带返回参数的aop --> <aop:after-returning method="afterReturning" pointcut="target(com.team.gaoguangjin.springinaction.schemaAspectAop.PlayGameImp)" returning="retVal" /> <aop:around method="aroundMethod" pointcut="execution(* playLOL(..)) and within(com.team.gaoguangjin.springinaction.schemaAspectAop.PlayGameImp)" /> </aop:aspect> </aop:config> <!-- 基于schemaAspectAop的配置切面--> <bean id="playGameAfterAdvice" class="com.team.gaoguangjin.springinaction.schemaAspectAop.PlayGameAfterAdvice" /> <aop:config proxy-target-class="true"> <aop:advisor advice-ref="playGameAfterAdvice" pointcut="execution(* com..*.playLOL(..))"/> </aop:config> </bean>
测试就和普通测试一样略。。。。
- Spring之Spring AOP
- Spring AOP之aop:config
- Spring AOP之ThrowsAdvice
- Spring AOP之ThrowsAdvice
- Spring之AOP IOC
- Spring总结之AOP
- Spring总结之AOP
- Spring AOP之Jruby
- Spring AOP 之 AfterAdviceDemo
- Spring AOP 之 AfterAdviceDemo2
- Spring AOP 之 AfterAdviceDemo3
- Spring AOP 之 AroundAdviceDemo
- Spring AOP 之 AroundAdviceDemo2
- Spring AOP 之 AroundAdviceDemo3
- Spring AOP 之 BeforeAdviceDemo
- Spring AOP 之 BeforeAdviceDemo2
- Spring AOP 之 BeforeAdviceDemo3
- Spring AOP 之 ControlFlowDemo
- log delphi
- Activity动画
- [华为机试练习题]19.字符串最后一个单词的长度
- 数据库连接池和Tomcat连接池的配置问题
- 清理oracle的归档日志
- spring之AOP
- ArduinoYun教程之通过网络为Arduino Yun编程
- 【MyBatis框架】配置文件-resultMap总结
- async和await异步操作
- Ubuntu下用apt-get安装最新版本的Redis
- 【MyBatis框架】高级映射-延迟加载
- Move blog from 51testing to cdsn
- 简单构建一个二叉树并且产生镜像
- 欢迎使用CSDN-markdown编辑器