AOP的实现有三种方式:
l aop底层将采用代理机制进行实现。
l 接口 + 实现类 :spring采用 jdk 的动态代理Proxy。
l 实现类:spring 采用 cglib字节码增强。
一.手工方式
1.JDK动态代理
JDK动态代理 对“装饰者”设计模式 简化。使用前提:必须有接口
1.目标类:接口 + 实现类
2.切面类:用于存通知 MyAspect
3.工厂类:编写工厂生成代理
4.测试
1.目标类
UserService.java
package com.zk.a_jdk;
public interface UserService {
public void addUser();
public void updateUser();
public void deleteUser();
}
UserServiceImpl.java
package com.zk.a_jdk;
public class UserServiceImpl implements UserService{
@Override
public void addUser() {
// TODO Auto-generated method stub
System.out.println("proxy addUser");
}
@Override
public void updateUser() {
// TODO Auto-generated method stub
System.out.println("proxy updateUser");
}
@Override
public void deleteUser() {
// TODO Auto-generated method stub
System.out.println("proxy deleteUser");
}
}
2.切面类
MyAspect.java
package com.zk.a_jdk;
public class MyAspect {
public void before(){
System.out.println("鸡头");
}
public void after(){
System.out.println("牛后");
}
}
3.工厂
package com.zk.a_jdk;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class MyBeanFactory {
//手工代理
public static UserService createService(){
//1.目标类
final UserService userservice=new UserServiceImpl();
//2.切面类
final MyAspect myAspect=new MyAspect();
//3.代理类:将目标类(切入点)和切面类(通知)结合-->切面
//Proxy.newProxyInstance
/*
* 参数一:loader类加载器,动态代理类,运行时创建,任何类都需要类加载器将其加载至内存。
* 一般情况下:当前类,class.getClassLoader();
* 目标类实例:getClass().get...
* 参数二:interfaces,代理类需要实现的所有接口
* 方式一:目标类实例.getClass().getInterfaces();注意:只能获得自己的接口,获得不到父元素的接口
* 方式二:new Class[]{UserService.class}
* 例如:jdbc驱动
* 参数三:InvocationHandler 处理类,接口,必须进行实现类,一般采用匿名内部类
* 提供invoke方法,代理类每一个方法执行时,都将去调用invoke
* 参数三.1.Object proxy代理对象
* 参数三.2.Method method 代理对象当前方法的描述对象(反射)
* 执行方法方法名:method.getName();
* 执行方法:method.invoke(对象,实际参数)
* 参数三.3 Object[] args 方法实际参数
*/
UserService proxyService=(UserService)Proxy.newProxyInstance
(MyBeanFactory.class.getClassLoader(),
userservice.getClass().getInterfaces(), new InvocationHandler(){
@Override
public Object invoke(Object proxy, Method method,
Object[] args) throws Throwable {
// TODO Auto-generated method stub
//前执行
myAspect.before();
//执行目标类的方法
Object obj=method.invoke(userservice, args);
//后执行
myAspect.after();
return null;
}
});
return proxyService;
}
}
4.测试类
package com.zk.a_jdk;
import org.junit.Test;
public class TestJDK {
@Test
public void test(){
UserService userservice=MyBeanFactory.createService();
userservice.addUser();
userservice.deleteUser();
userservice.updateUser();
}
}
运行效果:
2. CGLIB字节码增强
l 没有接口,只有实现类。
l 采用字节码增强框架 cglib,在运行时 创建目标类的子类,从而对目标类进行增强。
l 导入jar包:
1.目标类
UserService.java
package com.zk.a_jdk;
public interface UserService {
public void addUser();
public void updateUser();
public void deleteUser();
}
UserServiceImpl.java
package com.zk.a_jdk;
public class UserServiceImpl implements UserService{
@Override
public void addUser() {
// TODO Auto-generated method stub
System.out.println("proxy addUser");
}
@Override
public void updateUser() {
// TODO Auto-generated method stub
System.out.println("proxy updateUser");
}
@Override
public void deleteUser() {
// TODO Auto-generated method stub
System.out.println("proxy deleteUser");
}
}
2.切面类
MyAspect.java
package com.zk.a_jdk;
public class MyAspect {
public void before(){
System.out.println("鸡头");
}
public void after(){
System.out.println("牛后");
}
}
3.MyBeanFactory.java工厂类
package com.zk.b_cglib;
import java.lang.reflect.Method;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
public class MyBeanFactory {
//手工代理
public static UserService createService(){
//1.目标类
final UserServiceImpl userservice=new UserServiceImpl();
//2.切面类
final MyAspect myAspect=new MyAspect();
/*3.代理类
* 采用字节码增强框架-cglib,程序运行时创建目标类的子类,从而对目标类进行增强
* 导入jar包
* intercept等效于jdk中invoke方法
* 参数一二三 与invoke相同
* 参数四方法的代理
*/
Enhancer enhance=new Enhancer();
//确定父类
enhance.setSuperclass(userservice.getClass());
enhance.setCallback(new MethodInterceptor(){
//设置回调函数,MethodInterceptor接口等效 jdk InvocationHandler接口
@Override
public Object intercept(Object proxy, Method method, Object[] args,
MethodProxy methodproxy) throws Throwable {
// TODO Auto-generated method stub
//前before
myAspect.before();
//执行目标类的方法
Object obj=method.invoke(userservice, args);
//执行代理类的父类
methodproxy.invokeSuper(proxy, args);
//后after
myAspect.after();
return null;
}
});
//创建代理
UserServiceImpl proxyservice=(UserServiceImpl) enhance.create();
return proxyservice;
}
}
4.TestCglib.java测试
package com.zk.b_cglib;
import org.junit.Test;
public class Testcglib {
@Test
public void test(){
UserService userservice=MyBeanFactory.createService();
userservice.addUser();
userservice.deleteUser();
userservice.updateUser();
}
}
运行效果图:
二.半自动方式
让spring 创建代理对象,从spring容器中手动的获取代理对象。
导入jar包:
AOP:AOP联盟(规范)、spring-aop (实现)
1.目标类
UserService.java
public interface UserService {
public void addUser();
public void updateUser();
public void deleteUser();
}
UserServiceImpl.java
package com.zk.springAop;
public class UserServiceImpl implements UserService{
@Override
public void addUser() {
// TODO Auto-generated method stub
System.out.println("addUser");
}
@Override
public void updateUser() {
// TODO Auto-generated method stub
System.out.println("updateUser");
}
@Override
public void deleteUser() {
// TODO Auto-generated method stub
System.out.println("deleteUser");
}
}
2.切面类
/**
* 切面类中确定通知,需要实现不同接口,接口就是规范,从而就确定方法名称。
* * 采用“环绕通知” MethodInterceptor
*
*/
public class MyAspect implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
System.out.println("前3");
//手动执行目标方法
Object obj = mi.proceed();
System.out.println("后3");
return obj;
}
}
3.spring配置
<?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:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
">
<!-- 创建目标类 -->
<bean id="userserviceid" class="com.zk.factorybean.UserServiceImpl"></bean>
<!-- 创建切面类 -->
<bean id="aspectid" class="com.zk.factorybean.MyAspect"></bean>
<!-- 创建代理类
使用工厂bean factorybean,底层调用getObject(), 返回特殊bean
ProxyBeanFactory用于创建代理工厂bean,生成特殊代理对象
interface确定接口
通过Array确定多个值
只有一个值时,value=""
target确定目标类
interceptorNames:通知切面类名称,类型String[],如果设置一个值, value=""
optimize:强制使用cglib
<property name="optimized value="true"></property>
底层机制:
如果目标类有接口,采用jdk代理
如果没有接口,采用cglib代理
如果声明式optimize=true,都使用cglib
-->
<bean id="proxyServiceid" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="interfaces" value="com.zk.factorybean.UserService"></property>
<property name="target" ref="userserviceid"></property>
<property name="interceptorNames" value="aspectid"></property>
</bean>
</beans>
4.Testfactorybean.java
package com.zk.factorybean;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Testfactorybean {
@Test
public void test(){
String path="com/zk/factorybean/ApplicationContext.xml";
ApplicationContext ac=new ClassPathXmlApplicationContext(path);
UserService userservice=(UserService) ac.getBean("proxyServiceid");
userservice.addUser();
userservice.deleteUser();
userservice.updateUser();
}
}
运行效果:
三.spring aop编程:全自动
从spring容器获得目标类,如果配置aop,spring将自动生成代理。
要确定目标类,aspectj 切入点表达式,导入jar包spring-framework-3.0.2.RELEASE-dependencies\org.aspectj\com.springsource.org.aspectj.weaver\1.6.8.RELEASE
1.目标类
UserService.java
public interface UserService {
public void addUser();
public void updateUser();
public void deleteUser();
}
UserServiceImpl.java
package com.zk.springAop;
public class UserServiceImpl implements UserService{
@Override
public void addUser() {
// TODO Auto-generated method stub
System.out.println("addUser");
}
@Override
public void updateUser() {
// TODO Auto-generated method stub
System.out.println("updateUser");
}
@Override
public void deleteUser() {
// TODO Auto-generated method stub
System.out.println("deleteUser");
}
}
2.切面类
/**
* 切面类中确定通知,需要实现不同接口,接口就是规范,从而就确定方法名称。
* * 采用“环绕通知” MethodInterceptor
*
*/
public class MyAspect implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
System.out.println("前3");
//手动执行目标方法
Object obj = mi.proceed();
System.out.println("后3");
return obj;
}
}
3.spring配置
<?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:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
">
<!-- 创建目标类 -->
<bean id="userserviceid" class="com.zk.springAop.UserServiceImpl"></bean>
<!-- 创建切面类 -->
<bean id="aspectid" class="com.zk.springAop.MyAspect"></bean>
<!-- Aop编程
1.导入命名空间
2.使用<aop:config>进行配置
proxy-target-class="true"声明是使用cglib代理
<aop:pointcut>:切入点,从目标对象上获取具体的方法
<aop:advisor>特殊的切面,只有一个通知和一个切入点
advise-ref 通知引用
pointcut-ref 切入点引用
advisor通知
3.切入点表达式
execution(* com.zk.springAop.*.*(..))
选择方法 *表示返回值任意 包 类名任意. 方法名任意 . 参数任意 .
-->
<aop:config>
<aop:pointcut expression="execution(* com.zk.springAop.*.*(..))" id="myPointCut"/>
<aop:advisor advice-ref="aspectid" pointcut-ref="myPointCut"/>
</aop:config>
</beans>