AOP简介
- AOP Aspect Oriented Programing 面向切面编程
- AOP采取横向抽取机制,取代了传统纵向继承体系重复性代码(如性能监视、事务管理、安全检查、缓存等)
-
AOP横向抽取与传统纵向继承对比图
图片.png - Spring AOP使用纯Java实现,不需要专门的编译过程和类加载器,在运行期通过代理方式向目标类织入增强代码。
AOP相关术语
- Joinpoint(连接点):所谓的连接点是指那些被拦截到的点。在Spring中,这些点指的是方法,Spring只支持方法类型的连接点。
- Pointcut(切入点):所谓的切入点是指我们要对哪些Joinpoint进行拦截的定义。
- Advice(通知/增强):所谓通知是指拦截到Joinpoint之后要做的事情就是通知。通知分为前置通知,后置通知,异常通知,最终通知,环绕通知(切面要完成的功能)。
- Introduction(引介):引介是一种特殊的通知,在不修改类代码的前提下,在运行期为类动态地添加一些方法或Field。
- Target(目标对象):代理的目标对象
- Weaving(织入):是指把增强应用到目标对象来创建新的代理对象的过程。Spring采用动态代理织入,而AspectJ采用编译期织入和类装载期织入。
- Proxy(代理):一个类被AOP织入增强后,就产生一个结果代理类。
-
Aspect(切面):是切入点和通知(引介)的结合。
图片.png
AOP底层实现:JDk的动态代理
只能对实现了接口的类进行动态代理
- UserDao接口
package com.alan.aop.demo1;
public interface UserDao {
public void save();
public void uodate();
public void delete();
public void find();
}
- UserDaoImpl实现类
package com.alan.aop.demo1;
public class UserDaoImpl implements UserDao {
@Override
public void save() {
System.out.println("保存用户。。。");
}
@Override
public void uodate() {
System.out.println("修改用户。。。");
}
@Override
public void delete() {
System.out.println("删除用户。。。");
}
@Override
public void find() {
System.out.println("查询用户。。。");
}
}
- 代理类
package com.alan.aop.demo1;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* UserDao代理类
*/
public class MyJdkProxy implements InvocationHandler {
private UserDao userDao;
//通过构造方法传入要代理的类
public MyJdkProxy(UserDao userDao){
this.userDao = userDao;
}
//产生代理类(对实现接口类产生代理)
public Object createProxy(){
//需要传入三个参数:类的加载器、类实现的接口、InvocationHandler接口
Object proxy = Proxy.newProxyInstance(userDao.getClass().getClassLoader(),userDao.getClass().getInterfaces(),this);
return proxy;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if("save".equals(method.getName())){
System.out.println("权限校验。。。");
return method.invoke(userDao,args);
}
return method.invoke(userDao,args);
}
}
- 测试类
package com.alan.aop.demo1;
import org.junit.Test;
public class SpringDemo1 {
@Test
public void demo1(){
UserDao userDao = new UserDaoImpl();
//创建代理
UserDao proxy = (UserDao) new MyJdkProxy(userDao).createProxy();
proxy.save();
proxy.uodate();
proxy.delete();
proxy.find();
}
}
AOP的底层实现:CGLIB的动态代理
- 对于不使用接口的业务类,无法使用JDK动态代理
- CGLIB采用非常底层字节码技术,可以为一个类创建子类,解决无接口代理问题
- 实体类
package com.alan.aop.demo2;
public class ProductDao {
public void save() {
System.out.println("保存用户。。。");
}
public void uodate() {
System.out.println("修改用户。。。");
}
public void delete() {
System.out.println("删除用户。。。");
}
public void find() {
System.out.println("查询用户。。。");
}
}
- 代理类
package com.alan.aop.demo2;
import com.alan.aop.demo1.MyJdkProxy;
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 MyCglibProxy implements MethodInterceptor {
private ProductDao productDao;
//构造方法传入ProductDao对象
public MyCglibProxy(ProductDao productDao){
this.productDao = productDao;
}
//创建方法生成代理
public Object createProxy(){
//1、创建核心类
Enhancer enhancer = new Enhancer();
//2、设置父类
enhancer.setSuperclass(productDao.getClass());
//3、设置回调(this代表当前对象,对实现接口的调用)
enhancer.setCallback(this);
//4、生成代理
Object proxy = enhancer.create();
return proxy;
}
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
if("save".equals(method.getName())){
System.out.println("用户校验。。。。");
return methodProxy.invokeSuper(proxy,args);
}
//invokeSuper调用父类的方法
return methodProxy.invokeSuper(proxy,args);
}
}
- 测试类
package com.alan.aop.demo2;
import org.junit.Test;
public class SpringDemo2 {
@Test
public void demo1(){
ProductDao productDao = new ProductDao();
ProductDao proxy = (ProductDao) new MyCglibProxy(productDao).createProxy();
proxy.delete();
proxy.find();
proxy.save();
proxy.uodate();
}
}
Spring代理实现
图片.png图片.png
Spring AOP增强类型
图片.png 图片.pngSpring AOP切面类型
图片.png- StudentDao接口类
package com.alan.aop.demo3;
public interface StudentDao {
public void save();
public void update();
public void delete();
public void find();
}
- StudentDaoImpl接口实现类
package com.alan.aop.demo3;
public class StudentDaoImpl implements StudentDao {
@Override
public void save() {
System.out.println("学生保存。。。");
}
@Override
public void update() {
System.out.println("学生修改。。。");
}
@Override
public void delete() {
System.out.println("学生保存。。。");
}
@Override
public void find() {
System.out.println("学生查询。。。");
}
}
- 测试类
package com.alan.aop.demo3;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import javax.annotation.Resources;
//通过注解简化测试。不需要在代码中通过ApplicationContext对象进行xml配置了
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class SpringDemo3 {
@Autowired
@Qualifier("studentDaoProxy")
private StudentDao studentDao;
@Test
public void demo1(){
studentDao.delete();
studentDao.find();
studentDao.save();
studentDao.update();
}
}
- xml配饰文件
<!--前置通知类型===================-->
<bean id="myBeforeAdvice" class="com.alan.aop.demo3.MyBeforeAdvice"></bean>
<!--Spring AOP产生代理对象-->
<bean id="studentDaoProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<!--配置目标类-->
<property name="target" ref="studentDao"></property>
<!--配置要实现的接口-->
<property name="proxyInterfaces" value="com.alan.aop.demo3.StudentDao"></property>
<!--配置增强类型,采用拦截的名称-->
<property name="interceptorNames" value="myBeforeAdvice"></property>
</bean>
- MyBeforeAdvice增强实现类
package com.alan.aop.demo3;
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
public class MyBeforeAdvice implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] objects, Object o) throws Throwable {
System.out.println("前置增强。。。。");
}
}
网友评论