什么是AOP?
-面向切面编程
-它是一种思想,可在不改变程序源码的情况下为程序添加额外的功能。
-允许通过分离应用的业务逻辑与系统级服务进行内聚性的开发。应用对象只实现业务逻辑即可,并不负责其他的系统级关注点。
-AOP专门用于处理系统中分布于各个模块中的交叉关注点的问题,在J2EE应用中,常常通过AOP来处理一些具有横切性质的系统级服务,如事务管理、安全检查、缓存、对象池管理等,AOP已经成为一种非常常用的解决方案。
AOP的发展过程?
-静态AOP:Aspect形式,通过特定的编译器,将实现后的Aspect编译并织入到系统的静态类中
-动态AOP:AOP的织入过程在系统运行开始之后进行,而不是预先编译到系统中
AOP术语?
-连接点:程序执行的某个特定位置,比如类初始化前、类初始化后、方法调用前、方法调用后等
-切点:通过切点来定位特定的连接点
-增强:织入到目标类连接点上的一段程序代码
-目标对象:增强逻辑的织入目标类
-引介:是一种特殊的增强,它为类添加一些属性和方法
-织入:为增强添加目标类的具体连接点上的过程
-代理:一个类被AOP织入增强后,会产生一个结果类,该类融合了原类和增强逻辑的代理类
-切面:由切点和增强组成,既包括了横切逻辑的定义,也包括了连接点的定义
AOP的原理剖析?
-AOP代理其实是由AOP框架动态生成的一个对象,该对象可作为目标对象使用,AOP代理所包含的方法与目标对象的方法如下图所示:
使用AOP的步骤是:
定义普通业务组件 ---> 定义切入点 ---> 定义增强处理
代理对象的方法 = 增强处理 + 被代理对象的方法
AOP的通俗理解?
-一个组件A,不关心其他常用的服务组件B,但是这个组件A使用组件B的时候,不是组件A自身去调用,而是通过配置等其他方式,比如Spring中可以通过xml配置文件。这样就使得A压根就不需要知道服务组件B是怎样的,爱存在不存在,爱怎么存在都与A无关。A只关心自己的业务逻辑,具体A使用B的时候,配置文件去做,与具体的A组件无关。
AOP的实现方法?
(1)利用Proxy实现AOP功能 (JDK动态代理)
采用Proxy类方法,基本流程为:主函数--->代理--->目标对象的方法。对于Proxy类有一个使用前提,就是目标对象必须实现接口,否则不能使用这个方法。
实现AOP功能步骤如下:
创建接口:StudentInterface.java
创建接口实现类:StudentBean.java
创建代理工厂:ProxyFactory.java
public interface StudentInterface {
public void print();
}
public class StudentBean implements StudentInterface {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public StudentBean() {
}
public StudentBean(String name) {
super();
this.name = name;
}
@Override
public void print() {
System.out.println("hi student.");
}
}
public class ProxyFactory implements InvocationHandler {
private Object object;
public Object createStudentProxy(Object obj) {
this.object = obj;
//创建并返回代理
return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj
.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
StudentBean studentBean = (StudentBean) object;
Object obj = null;
if(studentBean.getName() != null){
obj = method.invoke(object, args);
}else{
System.out.println("学生姓名为空,代理类已经进行拦截.");
}
return obj;
}
}
public class Test001 {
public static void main(String[] args) {
StudentInterface s1 = new StudentBean();
ProxyFactory proxyFactory = new ProxyFactory();
StudentInterface s2 = (StudentInterface) proxyFactory
.createStudentProxy(s1);
s2.print();
}
}
目标对象必须实现接口
返回创建的代理对象
重写invoke()方法
限制条件放在invoke()方法中
(2)利用CGLIB实现AOP功能(CGLIB动态代理)
CGLIB(code generation library)是一个开源项目,它是一个强大的、高性能、高质量的code生成类库,它可以在运行期间扩展Java类和实现Java接口。
实现AOP功能步骤如下所示:
引入jar包
创建实体类
创建CGLIB代理类
创建入口类进行测试
public class StudentBean {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public StudentBean() {
}
public StudentBean(String name) {
super();
this.name = name;
}
public void print() {
System.out.println("hi student.");
}
}
public class CGLIBProxyFactory implements MethodInterceptor{
private Object object;
public Object createStudentProxy(Object obj){
this.object = obj;
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(obj.getClass());
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object proxy, Method method, Object[] args,
MethodProxy methodProxy) throws Throwable {
StudentBean stu = (StudentBean) object;
Object ret = null;
if(stu.getName() != null){
methodProxy.invoke(object, args);
}else{
System.out.println("学生姓名为空,方法已经被拦截.");
}
return ret;
}
}
public class Test002 {
public static void main(String[] args) {
StudentBean s1 = new StudentBean();
CGLIBProxyFactory cglibProxyFactory = new CGLIBProxyFactory();
StudentBean s2 = (StudentBean) cglibProxyFactory.createStudentProxy(s1);
s2.print();
}
}
(3)利用Spring XML文件配置方式实现AOP功能步骤如下:
引入jar包
配置AOP命名空间
创建目标对象类
创建切面
在配置文件中配置
创建入口类进行测试
public interface TrainStationAware {
//售票方法
public String sellTicket(String name);
//退票方法
public String returnTicket(String name);
}
public class TrainStation implements TrainStationAware{
@Override
public String sellTicket(String name) {
System.out.println(name + "购票成功");
return "ok";
}
@Override
public String returnTicket(String name) {
System.out.println(name + "退票成功");
return "ok2";
}
}
public class XmlAdvice {
/**
* 在核心业务执行前执行,不能阻止核心业务的调用。
*
* @param joinPoint
*/
private void doBefore(JoinPoint joinPoint) {
System.out.println("-----doBefore().invoke-----");
}
/**
* 手动控制调用核心业务逻辑,以及调用前和调用后的处理,
*
* 注意:当核心业务抛异常后,立即退出,转向After Advice 执行完毕After Advice,再转到Throwing Advice
*
* @param pjp
* @return
* @throws Throwable
*/
private Object doAround(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("-----doAround().invoke-----");
MethodSignature ms = (MethodSignature) pjp.getSignature();
Method method = ms.getMethod();
Object retVal = null;
if("returnTicket".equals(method.getName())){
System.out.println("代理售票点不能办理退票");
}else{
retVal = pjp.proceed();
}
System.out.println("-----End of doAround()------");
return retVal;
}
/**
* 核心业务逻辑退出后(包括正常执行结束和异常退出),执行此Advice
*
* @param joinPoint
*/
private void doAfter(JoinPoint joinPoint) {
System.out.println("-----doAfter().invoke-----");
}
/**
* 核心业务逻辑调用正常退出后,不管是否有返回值,正常退出后,均执行此Advice
*
* @param joinPoint
*/
private void doReturn(JoinPoint joinPoint) {
System.out.println("-----doReturn().invoke-----");
}
/**
* 核心业务逻辑调用异常退出后,执行此Advice,处理错误信息
*
* @param joinPoint
* @param ex
*/
private void doThrowing(JoinPoint joinPoint, Throwable ex) {
System.out.println("-----doThrowing().invoke-----");
System.out.println(" 错误信息:" + ex.getMessage());
}
}
<?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-2.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
<bean id="trainStationAware" class="com.bear.spring.aop.TrainStation"/>
<bean id="xmlHandler" class="com.bear.spring.aop.XmlAdvice" />
<aop:config>
<aop:aspect id="aspect" ref="xmlHandler">
<aop:pointcut id="pointUserMgr" expression="execution(* com.bear.spring.aop.*.*Ticket(..))"/>
<aop:before method="doBefore" pointcut-ref="pointUserMgr"/>
<aop:after method="doAfter" pointcut-ref="pointUserMgr"/>
<aop:around method="doAround" pointcut-ref="pointUserMgr"/>
<aop:after-returning method="doReturn" pointcut-ref="pointUserMgr"/>
<aop:after-throwing method="doThrowing" throwing="ex" pointcut-ref="pointUserMgr"/>
</aop:aspect>
</aop:config>
</beans>
@Test
public void test(){
ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
TrainStationAware tsa = (TrainStationAware) context.getBean("trainStationAware");
tsa.sellTicket("张三");
// tsa.returnTicket("李四");
}