AOP是什么?
AOP是OOP的延续,是Aspect Oriented Programming的缩写,意思是面向方面编程。AOP实际是GoF设计模式的延续,设计模式孜孜不倦追求的是调用者和被调用者之间的解耦,AOP可以说也是这种目标的一种实现。
面向方面编程 AOP(Aspect Oriented Programming)是一种“关注点(Concern)”分离技术,通过运用“方面(aspect)”这种程序设计单元,允许开发者使用结构化的设计和编码,反映出其对系统的认识方式。AOP使设计和编码更加模块化、更加具结构化,从而使关注点局部化而不是分散于整个系统中。同时,需要定义好关注点和系统其他部分的接口,从而真正达到“分离关注点,分而治之”的目的。
1、AOP终级目标
AOP终级目标就是能以更自然、更灵活的方式模拟现实世界,从原始的机器语言到过程语言再到面向对象的语言,编程语言一步步地用更自然的方式描述软个把。AOP是软件开发思想的下一个产物,但AOP的出现并不是要完全代替OOP,而仅仅是作为OOP的有益补充。
2、AOP 解决紧密耦合的难题
许多 Java 开发人员已经接受了面向方面编程(AOP)的非强制性风格和灵活性,特别是在用于建立高度松散和可扩展的企业系统时
在将商业需求转换成软件功能的快速开发周期中,面向方面是一种可以利用的强有力的设计原理。通过将首要的设计重点从面向对象编程(OOP)的传统化特性转移出来,AOP 和设计原理允许软件架构师用一种和面向对象相当而又互补的方式来考虑设计。
3、分散关注 将通用需求功能从不相关类之中分离出来;同时,能够使得很多类共享一个行为,一旦行为发生变化,不必修改很多类,只要修改这个行为就可以。
4、AOP超越面向对象编程和设计,正在成为软件开发的下一个圣杯。
使用AOP,你可以将处理aspect的代码注入主程序,通常主程序的主要目的并不在于处理这些aspect。AOP可以防止代码混乱。
AOP 与所有 Java 开发人员所使用的面向对象设计和编程并不矛盾,也不会替代它,相反,会对其给予补充。AOP 可以看成开发人员和研究团体超越软件工程中的面向对象编程(OOP)自然而然的下一步。
Aspect(切面): 是通知和切入点的结合,通知和切入点共同定义了关于切面的全部内容---它的功能、在何时和何地完成其功能
joinpoint(连接点):所谓连接点是指那些被拦截到的点。在spring中,这些点指的是方法,因为spring只支持方法类型的连接点.
Pointcut(切入点):所谓切入点是指我们要对那些joinpoint进行拦截的定义.
通知定义了切面的”什么”和”何时”,切入点就定义了”何地”.
Advice(通知):所谓通知是指拦截到joinpoint之后所要做的事情就是通知.通知分为前置通知,后置通知,异常通知,最终通知,环绕通知(切面要完成的功能)
Target(目标对象):代理的目标对象
Weaving(织入):是指把切面应用到目标对象来创建新的代理对象的过程.切面在指定的连接点织入到目标对象
Introduction(引入):在不修改类代码的前提下, Introduction可以在运行期为类动态地添加一些方法或Field.
代码实例:
1.模仿添加书籍的事务管理
1)新建Book的pojo类
package com.spring._0416service; public class Book { private String bookeName; private String author; private double price; public Book() { } public String getBookeName() { return bookeName; } public void setBookeName(String bookeName) { this.bookeName = bookeName; } public String getAuthor() { return author; } public void setAuthor(String author) { this.author = author; } public double getPrice() { return price; } public void setPrice(double price) { this.price = price; } }
2)这里模拟数据库的新增方法
package com.spring._0416service; public interface BookService { public void addBook(Book book); } package com.spring._0416service; public class BookServiceImpl implements BookService{ @Override public void addBook(Book book) { System.out.println(book.getBookeName()+" "+book.getAuthor()+" "+book.getPrice()); } }
3)准备事务切面类
package com.spring._0416service; /** * 事务切面类 * */ public class TransAspect { public void open(){ System.out.println("开启事务"); } public void commit(){ System.out.println("提交事务"); } }
4)配置applicationContext.xml
1.注入bookService和transAspect
<bean id="bookService" class="com.spring._0416service.BookServiceImpl"/> <bean id="transAspect" class="com.spring._0416service.TransAspect"/>
2.配置切面 (前置通知和后置通知)
<!--配置切面--> <aop:config> <!--order 用来多个排序--> <aop:aspect order="1" ref="transAspect"> <!--第一颗*代表任意返回值类型,第三颗*代表类的任意方法,两个.代表 任意参数--> <aop:pointcut id="cutPoint" expression="execution(* com.spring._0416service.*.*(..))"/> <aop:before method="open" pointcut-ref="cutPoint"/> <aop:after method="commit" pointcut-ref="cutPoint"/> </aop:aspect> </aop:config>
5)测试
import com.spring._0416service.Book; import com.spring._0416service.BookService; import com.spring._0416service.BookServiceImpl; import org.junit.Before; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class BookServiceTest { private BookService bookService; @Before public void init(){ ApplicationContext act=new ClassPathXmlApplicationContext("applicationContext.xml"); bookService=act.getBean("bookService",BookService.class); } @Test public void test(){ Book book=new Book(); book.setAuthor("海明威"); book.setBookeName("丧钟为谁而鸣"); bookService.addBook(book); } }
结果:
2.模拟权限验证
1)新建user的pojo类
package com.spring.homework1; public class User { private String username; private String password; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } }
2)service两个方法:查看view()方法和删除delete()方法
package com.spring.homework1; public interface UserService { public void view(User user); public void delete(User user); } package com.spring.homework1; public class UserServiceImpl implements UserService{ public void view(User user) { System.out.println(user.getUsername()+"查看该网站"); } public void delete(User user) { System.out.println(user.getUsername()+"执行删除"); } }
3)设置两个切面类(getArgs()方法:获取连接点方法运行时的入参列表,proceed()方法:通过反射执行目标对象的连接点处的方法,就是放行的意思)
package com.spring.homework1; import org.aspectj.lang.ProceedingJoinPoint; public class UserAspect1 { public Object check1(ProceedingJoinPoint point) throws Throwable { Object result=null; User user= (User) point.getArgs()[0]; if(user.getUsername().equals("ling")&&user.getPassword().equals("wutongshu")){ result= point.proceed(); System.out.println("当前的方法:"+point.getSignature().getName()+" check1"); }else if(user.getUsername().equals("miao")&&user.getPassword().equals("wutongshu")){ System.out.println("当前的方法:"+point.getSignature().getName()+" check1"); result=point.proceed(); }else{ System.out.println("sss权限不够,请重新登录"); System.out.println("当前的方法:"+point.getSignature().getName()+"check1"); } return result; } }
package com.spring.homework1; import org.aspectj.lang.ProceedingJoinPoint; public class UserAspect2 { public Object check2(ProceedingJoinPoint point) throws Throwable { Object result=null; User user= (User) point.getArgs()[0]; if(user.getUsername().equals("ling")&&user.getPassword().equals("wutongshu")){ System.out.println("当前的方法:"+point.getSignature().getName()+"check2"); result= point.proceed(); }else if(user.getUsername().equals("miao")&&user.getPassword().equals("wutongshu")){ System.out.println("当前的方法:"+point.getSignature().getName()+"check2"); System.out.println("权限不够,无法删除"); }else{ System.out.println("ss权限不够,请重新登录"); System.out.println("当前的方法:"+point.getSignature().getName()+"check2"); } return result; } }
4)配置xml (around 环绕通知)
<bean id="userService" class="com.spring.homework1.UserServiceImpl"/> <bean id="userAspect1" class="com.spring.homework1.UserAspect1"/> <bean id="userAspect2" class="com.spring.homework1.UserAspect2"/> <aop:config> <aop:aspect order="1" ref="userAspect1"> <aop:pointcut id="user1Point" expression="execution(* com.spring.homework1.UserServiceImpl.view(..))"/> <aop:around method="check1" pointcut-ref="user1Point"/> </aop:aspect> <aop:aspect order="2" ref="userAspect2"> <aop:pointcut id="user2Point" expression="execution(* com.spring.homework1.UserServiceImpl.delete(..))"/> <aop:around method="check2" pointcut-ref="user2Point"/> </aop:aspect> </aop:config>
5)测试
import com.spring.homework1.User; import com.spring.homework1.UserService; import org.junit.Before; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class UserServiceTest { private UserService userService; @Before public void init(){ ApplicationContext act=new ClassPathXmlApplicationContext("applicationContext.xml"); userService=act.getBean("userService",UserService.class); } @Test public void test(){ User user=new User(); user.setUsername("ling"); user.setPassword("wutongshu"); userService.view(user); userService.delete(user); } }
结果:
当我们切换成只能查看的用户
或者两者权限都没有的用户