AOP实现原理—动态代理&CGLib代理
下面以事务管理为例,手动实现动态代理和cglib代理。对于增删改查方法,都需要开启事务,再进行操作,最后关闭事务。动态代理或者cglib代理就可以把这些事务管理的公共代码进行抽取,不必在增删改查方法里都写上事务管理的代码了,通过代理对象调用增删改查方法的时候会自动加上事务管理的代码。
动态代理
只能为接口创建动态代理对象
UserService.java
package cn.ccnuacmhdu.service;
public interface UserService {
public abstract void add();
public abstract void delete();
public abstract void update();
public abstract void find();
}
UserServiceImp.java
package cn.ccnuacmhdu.service;
public class UserServiceImp implements UserService {
public void add() {
System.out.println("增加用户");
}
public void delete() {
System.out.println("删除用户");
}
public void update() {
System.out.println("更新用户");
}
public void find() {
System.out.println("查找用户");
}
}
UserServiceProxyFactory.java
package cn.ccnuacmhdu.proxy;
import java.lang.reflect.Proxy;
import cn.ccnuacmhdu.service.UserService;
public class UserServiceProxyFactory {
public static UserService getUserServiceProxy(UserService userService) {
MyInvocationHandler handler = new MyInvocationHandler();
handler.setUserService(userService);
return (UserService)Proxy.newProxyInstance(userService.getClass().getClassLoader(),
userService.getClass().getInterfaces(), handler);
}
}
MyInvocationHandler.java
package cn.ccnuacmhdu.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import cn.ccnuacmhdu.service.UserService;
public class MyInvocationHandler implements InvocationHandler{
private UserService userService;//被代理接口的对象(面向抽象编程,传入对象赋给UserService)
public void setUserService(UserService userService) {
this.userService = userService;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("打开事务");
Object result = method.invoke(userService, args);
System.out.println("关闭事务");
return result;
}
}
Demo.java
package cn.ccnuacmhdu.demo;
import org.junit.Test;
import cn.ccnuacmhdu.proxy.UserServiceProxyFactory;
import cn.ccnuacmhdu.service.UserService;
import cn.ccnuacmhdu.service.UserServiceImp;
public class Demo {
@Test
public void fun() {
UserService userService = new UserServiceImp();
UserService userServiceProxy = UserServiceProxyFactory.getUserServiceProxy(userService);
userServiceProxy.add();
}
}
cglib代理
可以对任何类生成代理,原理是对目标对象进行**继承代理**。
cglib代理的实现已经被整合到了spring核心包中,需要导入spring核心包。
UserServiceImp.java
package cn.ccnuacmhdu.service;
public class UserServiceImp implements UserService {
public void add() {
System.out.println("增加用户");
}
public void delete() {
System.out.println("删除用户");
}
public void update() {
System.out.println("更新用户");
}
public void find() {
System.out.println("查找用户");
}
}
MyMethodInterceptor.java
package cn.ccnuacmhdu.proxy;
import java.lang.reflect.Method;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
public class MyMethodInterceptor implements MethodInterceptor{
//obj:被代理对象,method:被代理对象的方法,arg方法参数,methodProxy:方法的代理
public Object intercept(Object obj, Method method, Object[] arg, MethodProxy methodProxy) throws Throwable {
System.out.println("打开事务");
Object result = methodProxy.invokeSuper(obj, arg);
System.out.println("关闭事务");
return result;
}
}
UserServiceProxyFactory.java
package cn.ccnuacmhdu.proxy;
import org.springframework.cglib.proxy.Enhancer;
import cn.ccnuacmhdu.service.UserService;
import cn.ccnuacmhdu.service.UserServiceImp;
public class UserServiceProxyFactory {
public static UserService getUserServiceProxy() {
Enhancer enhancer = new Enhancer();//enhancer负责生成某个对象的代理
enhancer.setSuperclass(UserServiceImp.class);//打入要被代理的对象
enhancer.setCallback(new MyMethodInterceptor());
UserService userServiceImpProxy = (UserService) enhancer.create();//创建代理对象
return userServiceImpProxy;
}
}
Demo.java
package cn.ccnuacmhdu.demo;
import org.junit.Test;
import cn.ccnuacmhdu.proxy.UserServiceProxyFactory;
import cn.ccnuacmhdu.service.UserService;
import cn.ccnuacmhdu.service.UserServiceImp;
public class Demo {
@Test
public void fun() {
UserService userService = new UserServiceImp();
UserService userServiceProxy = UserServiceProxyFactory.getUserServiceProxy();
userServiceProxy.add();
}
}
AOP相关名词
spring的AOP配置
(1)导包
spring-framework-3.0.2.RELEASE-dependencies\org.aspectj\com.springsource.org.aspectj.weaver\1.6.8.RELEASE
\spring-framework-3.0.2.RELEASE-dependencies\org.aopalliance\com.springsource.org.aopalliance\1.0.0
spring-framework-4.2.4.RELEASE-dist\spring-framework-4.2.4.RELEASE\libs
再加上spring核心包及日志包,所有包如下:
(2)准备目标对象
package cn.ccnuacmhdu.service;
public class UserServiceImp implements UserService {
public void add() {
System.out.println("增加用户");
}
public void delete() {
System.out.println("删除用户");
}
public void update() {
System.out.println("更新用户");
}
public void find() {
System.out.println("查找用户");
}
}
(3)准备通知
package cn.ccnuacmhdu.springAOP;
import org.aspectj.lang.ProceedingJoinPoint;
public class MyAdvice {
//前置通知:目标方法运行前调用
//后置通知:在目标方法运行之后调用(如果出现异常不会调用)
//环绕通知:在目标方法之前和之后都调用
//异常拦截通知:出现异常会调用
//后置通知:在目标方法运行后调用(无论有异常都调用)
public void before() {
System.out.println("前置通知:目标方法运行前调用");
}
public void afterReturing() {
System.out.println("后置通知:在目标方法运行之后调用(如果出现异常不会调用)");
}
public Object around(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("环绕通知:前部分");
Object proceed = pjp.proceed();
System.out.println("环绕通知:后部分");
return proceed;
}
public void afterThrowing() {
System.out.println("异常拦截通知:出现异常会调用");
}
public void after() {
System.out.println("后置通知:在目标方法运行后调用(无论有异常都调用)");
}
}
(4)织入
1.先导入beans的名字空间xsi。(之前已经导入了beans约束,这里就不导入了)
2.再导入aop约束及名字空间xsi。
3.书写配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd ">
<!-- 1.配置目标对象 -->
<bean name="UserServiceImp" class="cn.ccnuacmhdu.service.UserServiceImp"></bean>
<!-- 2.配置通知对象 -->
<bean name="MyAdvice" class="cn.ccnuacmhdu.springAOP.MyAdvice"></bean>
<!-- 3.将通知织入目标对象 -->
<aop:config>
<!-- 配置切入点
id:起个名字,随便起名,expression:将成为切入点的方法
public void cn.ccnuacmhdu.service.UserServiceImp.add()
void cn.ccnuacmhdu.service.UserServiceImp.add()//public可省略
* cn.ccnuacmhdu.service.UserServiceImp.add()//返回值任意,注意*之后要有空格
* cn.ccnuacmhdu.service.UserServiceImp.*()//UserServiceImp下的所有方法进行增强,空参方法
* cn.ccnuacmhdu.service.UserServiceImp.*(。。)//UserServiceImp下的所有方法进行增强,参数任意
* cn.ccnuacmhdu.service.*ServiceImp.*(..)//service包下以UserServiceImp结尾的所有类下的所有方法进行增强,参数任意
* cn.ccnuacmhdu.service。.*UserServiceImp.*(。。)//service包下及其所有子包下以UserServiceImp结尾的所有类下的所有方法进行增强,参数任意
-->
<aop:pointcut expression="execution(* cn.ccnuacmhdu.service.*ServiceImp.*(..))" id="pointcut"/>
<aop:aspect ref="MyAdvice">
<aop:before method="before" pointcut-ref="pointcut"/>
<aop:after-returning method="afterReturing" pointcut-ref="pointcut"/>
<aop:after-throwing method="afterThrowing" pointcut-ref="pointcut"/>
<aop:around method="around" pointcut-ref="pointcut"/>
<aop:after method="after" pointcut-ref="pointcut"/>
</aop:aspect>
</aop:config>
</beans>
(5)测试
package cn.ccnuacmhdu.demo;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import cn.ccnuacmhdu.service.UserService;
public class Demo {
@Test
public void fun() {
ApplicationContext ac = new ClassPathXmlApplicationContext("cn/ccnuacmhdu/springAOP/applicationContext.xml");
UserService userService = (UserService)ac.getBean("UserServiceImp");
userService.add();
}
}
附:工程架构