ps:spring-aop 都是与aspectJ(第三方的jar包,spring提供支持)一起使用,本文只是单纯的了解spring架构是怎么切面的
AOP 分为:
1.静态代理:使用AOP框架提供的命令进行编译,从而在编译阶段就可以生成AOP代理类,因此也称为编译时增强;静态代理一Aspectj为代表。
2.动态代理:在运行时借助于JDK动态代理,CGLIB等在内存中临时生成AOP动态代理类,因此也被称为运行时增强,Spring AOP用的就是动态代理。
Spring框架中用到就是JDK动态代理(有接口)或者是CGLIB代理(无接口)。
JDK动态代理
用的是JDK 自带的 java.lang.reflect.InvocationHandler
1、首先创建业务类
public interface UserDao {
public void select();
public void deleted();
}
public class UserDaoImpl implements UserDao {
@Override
public void select() {
System.out.println("查找User");
}
@Override
public void deleted() {
System.out.println("删除User");
}
}
2、创建代理类
// JDK 的动态代理
public class MyJdkProxy implements InvocationHandler {
private Object object;
public MyJdkProxy(Object object) {
this.object = object;
}
// 获得代理类
public Object createProxy( ){
// newProxyInstance(类加载器,类的接口,要执行的invoke方法)
Object proxy = Proxy.newProxyInstance(object.getClass().getClassLoader(),object.getClass().getInterfaces(),this);
return proxy;
}
// 具体的代理业务逻辑 写在这里
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if("select".equalsIgnoreCase(method.getName())){
System.out.println("-----代理-----");
}
return method.invoke(object,args);
}
}
3、application.xml 配置
<?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.xsd">
<bean id="userDao" class="com.aop.demo1.UserDaoImpl"/>
</beans>
4、测试类
@RunWith(SpringJUnit4ClassRunner.class) // 让测试运行于Spring测试环境
@ContextConfiguration(locations = {"classpath:applicationContext.xml"}) // 加载 applicationContext.xml配置文件
public class SpringAopDemo1 {
@Resource(name = "userDao")
private UserDao userDao;
@Test
public void test1() {
UserDao userDao = new UserDaoImpl();
MyJdkProxy myJdkProxy = new MyJdkProxy(userDao);
//获得代理的类
UserDao proxy = (UserDao) myJdkProxy.createProxy();
proxy.deleted();
proxy.select();
}
}
输出结果:
具体流程:
1、将要被代理的类以参数的形式,放入代理工厂类里面
2、然后调用代理工厂的createProxy(Object obj)创建UserDaoImpl类的代理类,在该方法内,调用Proxy.createProxy()方法创建代理对象。第一个参数是目标对象的类加载器,第二个参数是目标对象实现的接口,第三个参数传入一个InvocationHandler实例,该参数和回调有关系。
3、每当调用目标对象的方法的时候,就会回调该InvocationHandler实例的方法,也就是public Object invoke()方法,我们就可以把限制的条件放在这里,条件符合的时候,就可以调用method.invoke()方法真正的调用目标对象的方法,否则,则可以在这里过滤掉不符合条件的调用。
CGLIB代理
使用CGlib的方法和使用Proxy的方法差不多,只是Proxy创建出来的代理对象和目标对象都实现了同一个接口。而CGlib的方法则是直接继承了目标对象。
1、引入jar包 我的版本是: 4.3.9.RELEASE
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
2、创建业务类
public class StudentDao {
public void insert() {System.out.println("CGlib-I----插入学生---");}
public void delete() {
System.out.println("CGlib-D----删除学生---");
}
}
3、创建代理类
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
// cglib 动态代理
public class MyCglibProxy implements MethodInterceptor {
private Object object;
public MyCglibProxy(Object object) {
this.object = object;
}
// cglib创建代理
public Object createProxy(){
// 1、创建核心类
Enhancer enhancer = new Enhancer();
// 2、设置父类
enhancer.setSuperclass(object.getClass());
// 3、设置回调
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("insert".equalsIgnoreCase(method.getName())){
System.out.println("--这是插入的方法啦啦啦----");
}
return methodProxy.invokeSuper(proxy,args);
}
}
4、application.xml 配置 同上一个applicationContext一样 只是新增
<bean id="studentDao" class="com.aop.demo2.StudentDao"/>
5、测试类
@RunWith(SpringJUnit4ClassRunner.class) // 让测试运行于Spring测试环境
@ContextConfiguration(locations = {"classpath:applicationContext.xml"}) // 加载 applicationContext.xml配置文件
public class SpringAopDemo2 {
@Resource(name = "studentDao")
private StudentDao studentDao;
@Test
public void test1() {
StudentDao studentDao = new StudentDao();
MyCglibProxy myCglibProxy = new MyCglibProxy(studentDao);
//获得代理的类
StudentDao proxy = (StudentDao) myCglibProxy.createProxy();
proxy.delete();
proxy.insert();
}
}
输出结果:
具体流程:
1、将要被代理的类以参数的形式,放入代理工厂类里面
2、然后调用代理工厂的createProxy()创建StudentDao类的代理类,在这一步中,我们使用一个Enhancer类来创建代理对象,不再使用Proxy。使用Enhancer类,需要为其实例指定一个父类,也就是我们 的目标对象。这样,我们新创建出来的对象就是目标对象的子类,有目标对象的一样。除此之外,还要指定一个回调函数,这个函数就和Proxy的 invoke()类似。
总结
Spring中AOP代理由Spring的IOC容器负责生成、管理,其依赖关系也由IOC容器负责管理。因此,AOP代理可以直接使用容器中的其它bean实例作为目标,这种关系可由IOC容器的依赖注入提供。Spring创建代理的规则为:
1、默认使用Java动态代理来创建AOP代理,这样就可以为任何接口实例创建代理了
2、当需要代理的类不是代理接口的时候,Spring会切换为使用CGLIB代理,也可强制使用CGLIB