spring的AOP--面向切面编程

来源:互联网 发布:域名被墙如何实现301 编辑:程序博客网 时间:2024/05/21 13:22


AOP概念


1、AOP:aspect oriented programming 面向切面编程


2、AOP在spring中的作用

     提供声明式服务(声明式事务)

     允许用户实现自定义切面


3、AOP:在不改变原有代码的情况下,增加新的功能。


4、名词解释:

关注点:增加的某个业务。如日志、安全、缓存、事务、异常处理等。

        切   面 :一个关注点的模块化。

连接点:表示一个方法的执行。

通   知 :在切面的某个特定的连接点上执行的动作。

目标对象:被代理的对象--真实对象。

织   入 :把切面连接到其他的应用程序类型或者对象上,并创建一个被通知的对象。


5、使用spring实现aop


第一种实现方式: 通过spring的api来实现



前置通知


项目结构如下:




查看spring中文帮助文档,文档下载地址:《spring中文帮助文档.chm


中有关于aop通知的介绍,我们现在使用前置通知,从文档中可以知道我们要实现MethodBeforeAdvice,如下图:




Log代码:


package cn.myspring.log;import java.lang.reflect.Method;import org.springframework.aop.MethodBeforeAdvice;/** * 日志切面 */public class Log implements MethodBeforeAdvice {/** * @param method *            :被调用的方法对象 * @param args *            : 被调用的方法的参数 * @param target *            : 被调用方法的目标对象 */@Overridepublic void before(Method method, Object[] args, Object target)throws Throwable {System.out.println(target.getClass().getName() + "的" + method.getName()+ " 方法被执行");}}


UserService代码:


package cn.myspring.service;/** * 抽象角色 */public interface UserService {public void add() ;public void update() ;public void delete() ;public void search() ;}


UserServiceImpl代码:


package cn.myspring.service;/** * 真实角色 */public class UserServiceImpl implements UserService {@Overridepublic void add() {System.out.println("增加用户");}@Overridepublic void update() {System.out.println("修改用户");}@Overridepublic void delete() {System.out.println("删除用户");}@Overridepublic void search() {System.out.println("查询用户");}}


beans.xml代码:


<?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.xsd        http://www.springframework.org/schema/aop        http://www.springframework.org/schema/aop/spring-aop.xsd">   <bean id="userService" class="cn.myspring.service.UserServiceImpl"></bean><bean id="log" class="cn.myspring.log.Log"></bean><aop:config><!-- aop:pointcut切入点配置:execution() : 是表达式; *  : 表示所有返回值 ;位置 : cn.myspring.service.UserServiceImpl ;方法 : add() ;--><aop:pointcut expression="execution(* cn.myspring.service.UserServiceImpl.add())" id="pointcut"/><!-- aop:advisor : 告诉程序,切入点如嵌入的业务有哪些; advice-ref  : 对应的公共业务 ; pointcut-ref: 切入点。 --><aop:advisor advice-ref="log" pointcut-ref="pointcut"/></aop:config></beans>


Test类代码:


package com.myspring.test;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;import cn.myspring.service.UserService;public class Test {public static void main(String[] args) {ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml") ;UserService userService = (UserService) ac.getBean("userService") ;userService.add() ;}}

运行Test类,控制台打印信息:


2017-8-16 10:04:28 org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@2747ee05: startup date [Wed Aug 16 10:04:28 CST 2017]; root of context hierarchy2017-8-16 10:04:29 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions信息: Loading XML bean definitions from class path resource [beans.xml]2017-8-16 10:04:29 org.springframework.context.support.ClassPathXmlApplicationContext refresh警告: Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userService' defined in class path resource [beans.xml]: BeanPostProcessor before instantiation of bean failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor#0': Cannot resolve reference to bean 'pointcut' while setting bean property 'pointcut'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'pointcut': Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.aop.aspectj.AspectJExpressionPointcut]: No default constructor found; nested exception is java.lang.NoClassDefFoundError: org/aspectj/weaver/reflect/ReflectionWorld$ReflectionWorldExceptionException in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userService' defined in class path resource [beans.xml]: BeanPostProcessor before instantiation of bean failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor#0': Cannot resolve reference to bean 'pointcut' while setting bean property 'pointcut'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'pointcut': Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.aop.aspectj.AspectJExpressionPointcut]: No default constructor found; nested exception is java.lang.NoClassDefFoundError: org/aspectj/weaver/reflect/ReflectionWorld$ReflectionWorldExceptionat org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:479)at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:761)at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:867)at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:543)at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139)at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:83)at com.myspring.test.Test.main(Test.java:11)Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor#0': Cannot resolve reference to bean 'pointcut' while setting bean property 'pointcut'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'pointcut': Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.aop.aspectj.AspectJExpressionPointcut]: No default constructor found; nested exception is java.lang.NoClassDefFoundError: org/aspectj/weaver/reflect/ReflectionWorld$ReflectionWorldExceptionat org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:359)at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:108)at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1531)at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1276)at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:553)at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483)at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202)at org.springframework.aop.framework.autoproxy.BeanFactoryAdvisorRetrievalHelper.findAdvisorBeans(BeanFactoryAdvisorRetrievalHelper.java:92)at org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.findCandidateAdvisors(AbstractAdvisorAutoProxyCreator.java:102)at org.springframework.aop.aspectj.autoproxy.AspectJAwareAdvisorAutoProxyCreator.shouldSkip(AspectJAwareAdvisorAutoProxyCreator.java:103)at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.postProcessBeforeInstantiation(AbstractAutoProxyCreator.java:248)at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInstantiation(AbstractAutowireCapableBeanFactory.java:1037)at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.resolveBeforeInstantiation(AbstractAutowireCapableBeanFactory.java:1011)at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:473)... 10 moreCaused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'pointcut': Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.aop.aspectj.AspectJExpressionPointcut]: No default constructor found; nested exception is java.lang.NoClassDefFoundError: org/aspectj/weaver/reflect/ReflectionWorld$ReflectionWorldExceptionat org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1155)at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1099)at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:513)at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483)at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:325)at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:351)... 26 moreCaused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.aop.aspectj.AspectJExpressionPointcut]: No default constructor found; nested exception is java.lang.NoClassDefFoundError: org/aspectj/weaver/reflect/ReflectionWorld$ReflectionWorldExceptionat org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:85)at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1147)... 32 moreCaused by: java.lang.NoClassDefFoundError: org/aspectj/weaver/reflect/ReflectionWorld$ReflectionWorldExceptionat java.lang.Class.getDeclaredConstructors0(Native Method)at java.lang.Class.privateGetDeclaredConstructors(Class.java:2389)at java.lang.Class.getConstructor0(Class.java:2699)at java.lang.Class.getDeclaredConstructor(Class.java:1985)at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:80)... 33 moreCaused by: java.lang.ClassNotFoundException: org.aspectj.weaver.reflect.ReflectionWorld$ReflectionWorldExceptionat java.net.URLClassLoader$1.run(URLClassLoader.java:200)at java.security.AccessController.doPrivileged(Native Method)at java.net.URLClassLoader.findClass(URLClassLoader.java:188)at java.lang.ClassLoader.loadClass(ClassLoader.java:307)at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)at java.lang.ClassLoader.loadClass(ClassLoader.java:252)at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:320)... 38 more


造成报错的原因是因为缺少两个jar包:aopalliance-1.0.jar和aspectjweaver-1.8.8.jar,

这两个jar包的下载地址:《aop面向切面需要的jar包》


将这两个jar包放到项目中,如图:




然后再次运行Test,控制台打印信息如下:




说明spring的aop产生作用了。


接下里我们在Test代码中增加一行调用delete方法的代码,如下:


package com.myspring.test;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;import cn.myspring.service.UserService;public class Test {public static void main(String[] args) {ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml") ;UserService userService = (UserService) ac.getBean("userService") ;userService.add() ;System.out.println("----------------------------");userService.delete() ;}}


运行Test控制台打印信息如下:




我们发现调用的delete方法,并没有加上日志信息。


这是因为我们在beans.xml配置文件中,aop的日志配置,只配置了add方法,


如图:






如果想要UserServiceImpl类中的所有方法都起作用,那么配置应该改成*号,如下面的代码:


<?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.xsd        http://www.springframework.org/schema/aop        http://www.springframework.org/schema/aop/spring-aop.xsd">   <bean id="userService" class="cn.myspring.service.UserServiceImpl"></bean><bean id="log" class="cn.myspring.log.Log"></bean><aop:config><!-- aop:pointcut切入点配置:execution() : 是表达式; *  : 表示所有返回值 ;位置 : cn.myspring.service.UserServiceImpl ;方法 : * 表示UserServiceImpl类中的所有方法都起作用 ;--><aop:pointcut expression="execution(* cn.myspring.service.UserServiceImpl.*())" id="pointcut"/><!-- aop:advisor : 告诉程序,切入点如嵌入的业务有哪些; advice-ref  : 对应的公共业务 ; pointcut-ref: 切入点。 --><aop:advisor advice-ref="log" pointcut-ref="pointcut"/></aop:config></beans>


再次运行Test代码,控制台打印信息如下:




可以看到在add方法和delete方法的前面都打印了日志信息。


如果我们的方法有参数,那么就可以在beans.xml配置aop时,写上两个点,如下:




如果是某一个包下面的所有的类的所有方法都要使用aop嵌入日志信息,那么就可以写成如下:





后置通知


从spring中文帮助文档.chm中可以看到后置通知的实现类如下图:





在cn.myspring.log包下增加AfterLog类,代码如下:


package cn.myspring.log;import java.lang.reflect.Method;import org.springframework.aop.AfterReturningAdvice;public class AfterLog implements AfterReturningAdvice {/** * 目标方法执行后,执行的通知 *  * @param returnValue *            : 返回值 ; * @param method *            : 被调用的方法对象 ; * @param args *            : 被调用方法的参数 ; * @param target *            : 被调用的方法对象的目标对象 。 */@Overridepublic void afterReturning(Object returnValue, Method method,Object[] args, Object target) throws Throwable {System.out.println(target.getClass().getName() + "的" + method.getName()+ "被成功执行 , 返回值是 :" + returnValue);}}


在beans.xml中配置文件增加afterLog类的配置和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.xsd        http://www.springframework.org/schema/aop        http://www.springframework.org/schema/aop/spring-aop.xsd">   <bean id="userService" class="cn.myspring.service.UserServiceImpl"></bean><bean id="log" class="cn.myspring.log.Log"></bean><bean id="afterlog" class="cn.myspring.log.AfterLog"></bean><aop:config><!-- aop:pointcut切入点配置:execution() : 是表达式; *  : 表示所有返回值 ;位置 : cn.myspring.service.UserServiceImpl ;方法 : * 表示UserServiceImpl类中的所有方法都起作用 ;--><aop:pointcut expression="execution(* cn.myspring.service.*.*(..))" id="pointcut"/><!-- aop:advisor : 告诉程序,切入点如嵌入的业务有哪些; advice-ref  : 对应的公共业务 ; pointcut-ref: 切入点。 --><aop:advisor advice-ref="log" pointcut-ref="pointcut"/><aop:advisor advice-ref="afterlog" pointcut-ref="pointcut"/></aop:config></beans>


测试类Test代码如下:


package com.myspring.test;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;import cn.myspring.service.UserService;public class Test {public static void main(String[] args) {ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml") ;UserService userService = (UserService) ac.getBean("userService") ;userService.add() ;}}


运行Test代码,控制台打印信息如下:




AOP的重要性:


spring的aop就是将公共的业务(如:日志、安全等)和领域业务结合。当执行领域业务时,将会把公共业务加进、

来。实现公共业务的重复利用。领域业务更纯粹,程序员专注于领域业务。其本质还是动态代理。



第二种方式实现aop:自定义类来实现


项目结构如图:




Log日志类:


package cn.myspring.log;/** * 日志切面 */public class Log {public void before() {System.out.println("---方法执行前---");}public void after() {System.out.println("---方法执行后---");}}


UserService类:


package cn.myspring.service;/** * 抽象角色 */public interface UserService {public void add() ;public void update() ;public void delete() ;public void search(int a) ;}


UserServiceImpl类代码:


package cn.myspring.service;/** * 真实角色 */public class UserServiceImpl implements UserService {@Overridepublic void add() {System.out.println("增加用户");}@Overridepublic void update() {System.out.println("修改用户");}@Overridepublic void delete() {System.out.println("删除用户");}@Overridepublic void search(int a) {System.out.println("查询用户"+a);}}

beans.xml配置文件代码:


<?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.xsd        http://www.springframework.org/schema/aop        http://www.springframework.org/schema/aop/spring-aop.xsd">   <bean id="userService" class="cn.myspring.service.UserServiceImpl"></bean><bean id="log" class="cn.myspring.log.Log"></bean><aop:config><!-- 自定义aop配置ref : 关联Log日志类; --><aop:aspect ref="log"><aop:pointcut expression="execution(* cn.myspring.service.*.*(..))" id="pointcut"/><aop:before method="before" pointcut-ref="pointcut"/><aop:after method="after" pointcut-ref="pointcut"/></aop:aspect></aop:config></beans>

Test类代码:

package com.myspring.test;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;import cn.myspring.service.UserService;public class Test {public static void main(String[] args) {ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml") ;UserService userService = (UserService) ac.getBean("userService") ;userService.add() ;}}


运行Test类,控制台打印信息:





第三种实现方式:通过注解来实现


项目结构如下:




Log类代码如下:


package cn.myspring.log;import org.aspectj.lang.annotation.After;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Before;/** * 日志切面 */@Aspectpublic class Log {@Before("execution(* cn.myspring.service.*.*(..))")public void before() {System.out.println("---方法执行前---");}@After("execution(* cn.myspring.service.*.*(..))")public void after() {System.out.println("---方法执行后---");}}


UserServiceImpl代码:


package cn.myspring.service;/** * 抽象角色 */public interface UserService {public void add() ;public void update() ;public void delete() ;public void search(int a) ;}


UserServiceImpl代码:


package cn.myspring.service;/** * 真实角色 */public class UserServiceImpl implements UserService {@Overridepublic void add() {System.out.println("增加用户");}@Overridepublic void update() {System.out.println("修改用户");}@Overridepublic void delete() {System.out.println("删除用户");}@Overridepublic void search(int a) {System.out.println("查询用户"+a);}}


beans.xml代码:


<?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.xsd        http://www.springframework.org/schema/aop        http://www.springframework.org/schema/aop/spring-aop.xsd">   <bean id="userService" class="cn.myspring.service.UserServiceImpl"></bean><bean id="log" class="cn.myspring.log.Log"></bean><!-- 自动配置aop --><aop:aspectj-autoproxy /></beans>

Test类同上,运行后控制台打印信息:




当实现环绕通知时,我们在Log类中增加如下代码:


@Around("execution(* cn.myspring.service.*.*(..))")public void around(ProceedingJoinPoint jp) throws Throwable {System.out.println("环绕前");System.out.println("签名:"+jp.getSignature());//执行目标方法jp.proceed() ;System.out.println("环绕后");}


增加后Log类代码如图:




执行Test类代码,控制台打印信息如下:





























原创粉丝点击