什么是AOP
AOP的全称是 Aspect-OrientedProgramming,即面向切面编程(也称面向方面编程)。它是面向对象编程(OOP)的一种补充,目前已成为一种比较成熟的编程方式。
在通常的开发中,通常都会进行事务处理、日志记录等操作。虽然使用OOP可以通过组合或者继承等方法来表达到代码的重用,但如果要实现某个功能(如日志记录),同样的代码仍然会分散到各个方法中。这样,如果想要关闭某个功能,或者进行修改,就必须要修改所有相关的方法。这不但增加了开发人员的工作量,而且提高了代码的出错率。
为了解决这一问题,AOP思想随之产生。AOP采取横向抽取机制,将分散在各个方法中的重复代码提取出来,然后在程序编译或运行时,再将这些提取出来的代码应用到需要执行的地方。这种采用横向抽取机制的方式,采用传统的OOP思想显然是无法办到的,以为OOP只能实现父子关系的纵向重用。虽然AOP是一种新的编程思想,但却不是OOP的替代品,它只是OOP的延伸和补充。
一 JDK动态代理
1.创建接口
package com.kangxg.jdk;
public interface UserDao
{
public void addUser();
public void deleteUser();
}
2.创建接口实现类
public class UserDaoImpl implements UserDao{
public void addUser()
{
System.out.println("添加用户");
}
public void deleteUser()
{
System.out.println("删除用户");
}
}
3.创建切片类
package com.kangxg.aspect;
public class MyAspect {
public void check_Permissions(){
System.out.println("模拟检查权限。。。");
}
public void log(){
System.out.println("模拟记录日志。。。");
}
}
4.创建代理类
package com.kangxg.jdk;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import com.kangxg.aspect.MyAspect;
/**
*
* JDK 代理类
*
*/
public class JdkProxy implements InvocationHandler {
//声明目标类接口
private UserDao userDao;
//创建代理方法
public Object createProxy(UserDao userDao)
{
this.userDao = userDao;
// 类加载器
ClassLoader classLoader = JdkProxy.class.getClassLoader();
// 被代理对象实现的所以接口
@SuppressWarnings("rawtypes")
Class[] clazz = userDao.getClass().getInterfaces();
//使用代理类,进行增强,返回的是代理后的对象 (相当于OC中的消息转发)
return Proxy.newProxyInstance(classLoader, clazz, this);
}
/*
* 所有动态代理类的方法调用,都会交由invoke()方法去处理
* proxy 被代理后的对象
* method 将要被执行的方法信息(反射)
* args 执行方法时需要的参数
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable
{
// 声明切面
MyAspect myAspect = new MyAspect();
//前增强
myAspect.check_Permissions();
// 在目标类上调用方法,并传入参数
Object obj = method.invoke(userDao,args);
// 后增强
myAspect.log();
return obj;
}
}
5.创建测试类
package com.kangxg.jdk;
public class JdkTest {
public static void main(String[] args) {
//创建代理类
JdkProxy jdkProxy = new JdkProxy();
//创建目标对象
UserDao userDao = new UserDaoImpl();
// 从代理对象中获取增强后的目标对象
UserDao userDao1 = (UserDao)jdkProxy.createProxy(userDao);
// 执行方法
userDao1.addUser();
userDao1.deleteUser();
}
}
6 debug 执行程序
二 CGLIB代理
JDK动态代理的使用非常简单,但是它还有一定的局限性-使用动态代理的对象必须实现一个或多个接口。如果要对没有实现接口的类进行代理,那么可以使用CGLIB代理
CGLIB 是一个高性能开源的代码生成包,它采用非常底层的字节码技术,对指定的目标类生成一个子类,并对子类进行增强。在Spring的核心包中已经集成类CGLIB所需的包,无需再导入JAR包
1.创建被代理的类
package com.kangxg.cglib;
public class UserDao {
public void addUser()
{
System.out.println("cglib添加用户");
}
public void deleteUser()
{
System.out.println("cglib删除用户");
}
}
2.创建代理类
package com.kangxg.cglib;
import java.lang.reflect.Method;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import com.kangxg.aspect.MyAspect;
//代理类
public class CglibProxy implements MethodInterceptor {
public Object createProxy(Object target)
{
// 创建一个动态类对象
Enhancer enhancer = new Enhancer();
//确定需要增强的类,设置其父类
enhancer.setSuperclass(target.getClass());
//增加回调函数
enhancer.setCallback(this);
//返回创建的代理类
return enhancer.create();
}
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
// 声明切面
MyAspect myAspect = new MyAspect();
//前增强
myAspect.check_Permissions();
// 目标方法执行
Object obj = methodProxy.invokeSuper(proxy, args);
// 后增强
myAspect.log();
return obj;
}
}
3.创建测试类
package com.kangxg.cglib;
public class CglibTest {
public static void main(String[] args) {
//创建代理类
CglibProxy cglibProxy = new CglibProxy();
//创建目标对象
UserDao userDao = new UserDao();
// 从代理对象中获取增强后的目标对象
UserDao userDao1 = (UserDao)cglibProxy.createProxy(userDao);
// 执行方法
userDao1.addUser();
userDao1.deleteUser();
}
}
4.Debug执行程序
基于代理类的AOP
1.创建切片类
package com.kangxg.factorybean;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
//切片类
public class MyAspect implements MethodInterceptor{
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
check_Permissions();
Object obj = mi.proceed();
log();
return obj;
}
public void check_Permissions(){
System.out.println("factorybean 模拟检查权限。。。");
}
public void log(){
System.out.println("factorybean 模拟记录日志。。。");
}
}
2.创建配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd">
<!-- 目标类 -->
<bean id="userDao" class="com.kangxg.jdk.UserDaoImpl" />
<!-- 目标类 -->
<bean id="myAspect" class="com.kangxg.factorybean.MyAspect" />
<!-- 使用Spring代理工厂定义一个名称为userDaoProxy的代理对象 -->
<bean id="userDaoProxy" class="org.springframework.aop.framework.ProxyFactoryBean" >
<!-- 指定代理实现接口 -->
<property name="proxyInterfaces" value="com.kangxg.jdk.UserDao" />
<!-- 地丁目标对象 -->
<property name = "target" ref = "userDao"/>
<!-- 指定切面,植入环绕通知 -->
<property name = "interceptorNames" value ="myAspect" />
<!-- 指定代理方式,true :使用cglib,false(默认): 使用jdk动态代理 -->
<property name = "proxyTargetClass" value ="true" />
</bean>
</beans>
3.创建测试类
package com.kangxg.factorybean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.kangxg.jdk.UserDao;
public class ProxyFactoryBeanTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
String xmlPath = "com/kangxg/factorybean/applicationContext.xml";
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
UserDao userDao =(UserDao) applicationContext.getBean("userDaoProxy");
userDao.addUser();
userDao.deleteUser();
}
}
4 Debug运行程序
注意要加入:aopalliance-1.0.jar 包 下载地址 http://mvnrepository.com/artifact/aopalliance/aopalliance/1.0