学习目标:
1、了解Java的历史
2、为什么要学习Java语言
3、端正学习态度
学习过程:
一、什么是AOP编程
1、AOP思想
AOP是OOP的延续,是Aspect Oriented Programming的缩写,意思是面向切面编程。如何理解AOP,我们可以先看看在什么情况下使用AOP,比如:开发人员编写程序时,通常包含两种代码:1.和业务逻辑有关的代码,2.和业务逻辑关系不大的代码,例如日志、权限、异常处理、事务处理等。
当这两种代码都是写在一起时,不利于程序的维护。而AOP就是使这两种代码分离的思想。使用AOP,就不用在业务逻辑中实现与业务功能关系不大的代码,从而降低了两种代码的耦合性,达到易于维护和重用的目的。
AOP是一种思想,它和具体的实现技术无关。一般实现AOP可以使用代理模式,JDK1.3以后,Java提供了动态代理机制。通过动态代理机制,就可以很容易的实现AOP的思想。实际上,Spring的AOP就是建立在Java的代理机制之上。
AOP编程和OOP编程不是竞争关系,AOP不能替代OOP编程,OOP(Object Oriented Programming)对现代编程产生了深远的影响,已经非常成熟了,它能很好的解决软件系统中角色划分的问题。借助于面向对象的分析、设计和实现,开发人员可以将现实领域的实体转换成软件系统中的对象,从而很自然的完成从现实到软件的转换。但是OOP并不完美,也有其不足的地方。比如日志、权限、异常处理、事务处理等方面,当应用OOP将这些内容封装为对象的行为时,会产生大量的重复代码。
AOP编程可以把一个应用程序分为核心关注点和横切关注点,核心关注点和具体应用的功能相关,而横切关注点存在于整个系统范围内。OOP中组合的流向是从主关注点到横切关注点,而AOP组合流向是从横切关注点到主关注点,两者多关注的对象是不同的,所有两者能很好的共存,AOP是OOP的有益补充。
2、AOP的术语
AOP是从另外一个视角看待应用程序,和OOP一样有很多新的概念和看法,为了让大家能够更好的理解AOP思想,这里就简单介绍一下一些基本的概念。
(1)Aspect 切面
指在方法顺序执行的过程中,突然在其中加入一些业务操作(如日志,事务等),这样就类似在顺序的过程中添加了一个切面.切面是一个大的称呼,它可能还包括很多的小切点。一个关注点的模块化,这个关注点可能会横切多个对象。事务管理是J2EE应用中一个关于横切关注点的很好的例子。
(2)Joinpoint 连接点
在程序执行过程中某个特定的点,比如某方法调用的时候或者处理异常的时候。这个点可以是一个方法、一个属性、构造函数、类静态初始化块,甚至一条语句。在Spring AOP中,一个连接点总是表示一个方法的执行。
(3)Advice 通知
在切面(Aspect)的某个特定的连接点(Joinpoint)上执行的动作。Advice定义了切面中的实际逻辑(即实现),比如日志的写入的实际代码。换一种说法Advice是指在定义好的切入点处,所要执行的程序代码。
(4)Pointcut 切入点
切入点指一个或多个连接点(joinpoint),可以理解成连接点的集合.指明Advice在什么条件下才能被触发。Advice是通过Pointcut来连接和介入进你的JointPoint的。日志例子里面的doWork()就是切入点。表示要在这里加入Advice。
(5)Advisor (Pointcut和Advice的配置器)
包括Pointcut和Advice,是将Advice注入程序中Ponitcut位置的代码。
(6)Target Object
被一个或者多个切面(aspect)所通知(advise)的对象。也有人把它叫做 被通知(advised) 对象。 既然Spring AOP是通过运行时代理实现的,这个对象永远是一个 被代理(proxy)对象。
二、配置通知模式
下面我们先介绍一下使用通知模式的AOP的实现,比如有下面这样一个业务方法。
public class LoginBizImpl implements LoginBiz{ public Boolean login(String name, String password) { String str=null; //System.out.println(str.length()); System.out.println(name+"登陆的核心逻辑"); return true; } }
这个就是我们的核心关注点,那么先你该如何才能不修改原来的代码,但是可以在执行这个代码之前或者之后,又或者出现异常的时候执行其他的功能呢?比如需要记录日志等功能。这里我们可以分别配置通知模式,当然不是说一定要配置全部的通知,根据实际情况就可以了,这个是教学实例我们就把前置通知、返回后通知、抛出后通知和环绕通知都简单介绍一下。
(1)前置通知(Before advice):在切入点匹配的方法执行之前运行使用,
需要实现接口:implements MethodBeforeAdvice
并实现方法:
public void before(Method arg0, Object[] arg1, Object arg2)
throws Throwable {System.out.println(arg1[0]+ " 开始工作..");}
(2)返回后通知(After returning advice):在切入点匹配的方法返回的时候执行(之后运行)。
需要实现接口:Implements AfterReturningAdvice
并实现方法:
public void afterReturning(Object arg0, Method arg1, Object[] arg2,Object arg3) throws Throwable {System.out.println(arg2[0]+ " 完成工作..");}
(3)抛出后通知(throwing advice): 在切入点匹配的方法执行时抛出异常的时候运行。
需要实现接口:Implements ThrowsAdvice
并实现方法:
public void afterThrowing(Method method,Object[] args,Object target,Throwable subclass)
throws Throwable{
System.out.println(args[0]+ " 工作中抛出异常....");}
(4)环绕通知(Interception Around Advice):环绕通知既在切入点匹配的方法执行的前后都运行。并且,它可以决定这个方法在什么时候执行,如何执行,甚至是否执行。在环绕通知中,除了可以自由添加需要的横切功能以外,还需要负责主动调用连接点(通过proceed)来执行激活连接点的程序。 请尽量使用最简单的满足你需求的通知。(比如如果前置通知也可以适用的情况下,就不要使用环绕通知)
需要实现接口:Implements MethodInterceptor
分别建立四个类实现上面几个通知。
1、前置通知
public class BeforeAdvice implements MethodBeforeAdvice { public void before(Method method, Object[] arg1, Object arg2) throws Throwable { System.out.println(method.getName()); System.out.println("权限判断"); System.out.println( "尝试登陆了系统--日志记录" + new Date()); } }
2、返回后通知
public class AfterAdviceMy implements AfterReturningAdvice{ public void afterReturning(Object returnobject, Method arg1, Object[] arg2, Object arg3) throws Throwable { System.out.println("后置通知"+returnobject); } }
3、异常通知
public class ThrowAdvice implements ThrowsAdvice{ public void afterThrowing(Throwable throwable){ System.out.println("异常通知"); } }
4、环绕通知
public class MethodInter implements MethodInterceptor { public Object invoke(MethodInvocation methodInvocation) throws Throwable { System.out.println("环绕通知--前置"); Object object = null; try { object = methodInvocation.proceed();// 执行核心方法 } catch (Exception e) { System.out.println("环绕通知--异常"); } System.out.println("环绕通知--后置"); return object; } }
然后就需要在spring容器中配置,先配置核心逻辑类
<!-- 核心业务逻辑 --> <bean name="loginBiz" class="com.biz.impl.LoginBizImpl"></bean>
把上面几个通知类也配置在spring容器中。
<!-- 前置通知 --> <bean name="beforeAdvice" class="com.advice.BeforeAdvice"></bean> <!-- 后置通知 --> <bean name="afterAdviceMy" class="com.advice.AfterAdviceMy"></bean> <!-- 异常通知 --> <bean name="throwAdvice" class="com.advice.ThrowAdvice"></bean> <!-- 环绕通知 --> <bean name="methodInter" class="com.advice.MethodInter"></bean>
在配置一个代理工程类
<!-- 代理类 代理工厂 --> <bean name="loginBizProxySpring" class="org.springframework.aop.framework.ProxyFactoryBean"> <!-- 要代理的类 --> <property name="target" ref="loginBiz"></property> <!--通知 --> <property name="interceptorNames"> <list> <value>beforeAdvice</value> <value>afterAdviceMy</value> <value>throwAdvice</value> <value>methodInter</value> </list> </property> </bean>
写一个测试类,注意这个时候不能去原来的bean的业务了,得有代理类执行。
public class RunSpring { public static void main(String[] args) { ApplicationContext context=new FileSystemXmlApplicationContext("src/loginContext.xml"); //有代理类执行 LoginBiz loginBiz=(LoginBiz)context.getBean("loginBizProxySpring"); loginBiz.login("liubao", ""); } }