在前几次主要写了一些Ioc的配置和实现,这次就到了AOP(面向切面编程),说到AOP还得提一提OOP(面向对象编程)
OOP:核心思想是将客观存在的不同事物抽象成相互独立的类,然后把与事物相关的属性和行为封装到类里,并通过继承和多态来定义类彼此间的关系,最后通过操作类的实例来完成实际业务逻辑的功能需求。**OOP通过继承和多态会使程序之间的耦合度增高,不利于扩展程序。**
AOP:AOP可以对业务逻辑的各个部分进行隔离,**从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率**。主要的功能是:日志记录,性能统计,安全控制,事务处理,异常处理等等。AOP是OOP的一个扩展,用来解决OOP存在的一些缺陷。
OOP与AOP的区别:
1、面向目标不同:简单来说OOP是面向名词领域,AOP面向动词领域。
2、思想结构不同:OOP是纵向结构,AOP是横向结构(由AOP联盟组织提出)。
3、注重方面不同:OOP注重业务逻辑单元的划分,AOP偏重业务处理过程的某个步骤或阶段。
在简单的分析完AOP后,我们开始进入正题,为什么AOP使程序的耦合度降低扩展性增强了呢?因为AOP的实现原理就是采用的动态代理,它既保证了程序的各部分隔离有保证了功能的实现。
在SpringAOP中所实现的动态代理可以从类别上分为两种
一,基于JDK的动态代理(只能对实现接口的类产生代理)
利用JDK创建代理对象,然后实现代理,以前写过利用JDK动态代理的实例(利用动态代理实现字符集编码的自动调整),这种就不在这里举例子了,附上博客链接:https://blog.csdn.net/qq_42605968/article/details/86566681
二,基于Cglib实现的动态代理(用来补充JDK)
Cglib也可以在没有实现的类中产生代理
代码和解析如下
内部类实现:用匿名内部类实现
public PersonDao CreateProxy() {
// 创建cglib核心类对象
Enhancer enhancer = new Enhancer();
// 设置父类
enhancer.setSuperclass(PersonDao.class);
// 回调类似于invocation
// enhancer.setCallback(this);
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
if ("tellName".equals(method.getName())) {
System.out.println("实现代理,已进行增强");
return methodProxy.invokeSuper(o, objects);
}
return methodProxy.invokeSuper(o, objects);
}
});
PersonDao personDao = (PersonDao) enhancer.create();
return personDao;
}
接口实现:实现MethodInterceptor接口
package CglibTest;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class cglib implements MethodInterceptor {
public PersonDao CreateProxy() {
// 创建cglib核心类对象
Enhancer enhancer = new Enhancer();
// 设置父类
enhancer.setSuperclass(PersonDao.class);
// 回调类似于invocation
enhancer.setCallback(this);
// enhancer.setCallback(new MethodInterceptor() {
// @Override
// public Object intercept(Object proxy, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
PersonDao personDao = (PersonDao) enhancer.create();
return personDao;
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
if ("tellName".equals(method.getName())) {
System.out.println("实现代理,已进行增强");
return methodProxy.invokeSuper(o, objects);
}
return methodProxy.invokeSuper(o, objects);
}
}
测试类:
@Test
public void test(){
PersonDao personDao1 = new cglib().CreateProxy();
personDao1.tellName();
}
当然我这里也只是简单的介绍和使用,只是为了更好的了解AOP。
AOP入门
入门当然要熟悉AOP的一些术语了,我罗列了一些AOP术语在我的另一篇博客上,附上链接:https://blog.csdn.net/qq_42605968/article/details/86695041
熟悉了术语之后,那就用一个小例子来了解一下这些术语的用法,轻轻松松的入门。
1.建立如下的测试包结构并导入AspectJ的jar包,因为Spring中采用的AspectJ的开源框架,它做的AOP比Spring更易于使用。
2.实现测试结构
package AOP;
public interface PersonDao1 {
public void tellName();
public void tellAge();
}
package AOP;
public class PersonDaoimpl implements PersonDao1 {
@Override
public void tellName() {
System.out.println("tellName");
}
@Override
public void tellAge() {
System.out.println("tellAge");
}
}
package AOP;
public class MyAspect {
public void Inform(){
System.out.println("before infrormation");
}
}
package AOP;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import javax.annotation.Resource;
//Spring工厂和JUnit结合,省去了创建工厂的过程,测试更加方便
@RunWith(SpringJUnit4ClassRunner.class)
//配置xml
@ContextConfiguration("classpath:AOPCof.xml")
public class Test01 {
@Resource(name = "PersonDao1")
private PersonDao1 personDao;
@Test
public void test01(){
personDao.tellAge();
personDao.tellName();
}
}
xml配置,使用aop就要把aop加载进来,在设置切点时expression必须用execution表达式,切点配置 *代表任意返回值,…代表任意参数
实现步骤
1.先配置需要配置的bean
2.配置切点,需要把那个包下的那个方法设置为切点
3.配置切面,切面是多个通知和多个切入点的组合,可以选择通知的前后给切点设置通知
<?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="PersonDao1" class="AOP.PersonDaoimpl"></bean>
<bean id="MyAspect" class="AOP.MyAspect"></bean>
<aop:config>
<!--切点配置 *代表任意返回值,..代表任意参数-->
<aop:pointcut id="pointcut01" expression="execution(* AOP.PersonDaoimpl.tellName(..))" ></aop:pointcut>
<!--切面配置-->
<aop:aspect ref="MyAspect">
<aop:before method="Inform" pointcut-ref="pointcut01"></aop:before>
</aop:aspect>
</aop:config>
</beans>
给tellName之前设置的通知
这就是AOP的入门小案例的完整实现。
下一篇就细讲AOP的一些学问!