到目前为止,已经简单学习了Spring的Core模块、也会怎么与Struts2框架进行整合了….因而咱们就开启了Spring的AOP模块了…在讲解AOP模块以前,首先咱们来说解一下cglib代理、以及怎么手动实现AOP编程java
在讲解cglib以前,首先咱们来回顾一下静态代理和动态代理….我以前就写过了静态代理、动态代理的博文:http://blog.csdn.net/hon_3y/article/details/70655966spring
因为静态代理须要实现目标对象的相同接口,那么可能会致使代理类会很是很是多….很差维护—->所以出现了动态代理编程
动态代理也有个约束:目标对象必定是要有接口的,没有接口就不能实现动态代理…..—–>所以出现了cglib代理markdown
cglib代理也叫子类代理,从内存中构建出一个子类来扩展目标对象的功能!session
接下来咱们就讲讲怎么写cglib代理:app
//须要实现MethodInterceptor接口 public class ProxyFactory implements MethodInterceptor{ // 维护目标对象 private Object target; public ProxyFactory(Object target){ this.target = target; } // 给目标对象建立代理对象 public Object getProxyInstance(){ //1. 工具类 Enhancer en = new Enhancer(); //2. 设置父类 en.setSuperclass(target.getClass()); //3. 设置回调函数 en.setCallback(this); //4. 建立子类(代理对象) return en.create(); } @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("开始事务....."); // 执行目标对象的方法 Object returnValue = method.invoke(target, args); System.out.println("提交事务....."); return returnValue; } }
public class App { public static void main(String[] args) { UserDao userDao = new UserDao(); UserDao factory = (UserDao) new ProxyFactory(userDao).getProxyInstance(); factory.save(); } }
使用cglib就是为了弥补动态代理的不足【动态代理的目标对象必定要实现接口】框架
AOP 面向切面的编程:ide
下面咱们来看一段代码:函数
// 保存一个用户 public void add(User user) { Session session = null; Transaction trans = null; try { session = HibernateSessionFactoryUtils.getSession(); // 【关注点代码】 trans = session.beginTransaction(); // 【关注点代码】 session.save(user); // 核心业务代码 trans.commit(); //…【关注点代码】 } catch (Exception e) { e.printStackTrace(); if(trans != null){ trans.rollback(); //..【关注点代码】 } } finally{ HibernateSessionFactoryUtils.closeSession(session); ////..【关注点代码】 } }
public interface IUser { void save(); }
咱们一步一步来分析,首先咱们的UserDao有一个save()方法,每次都要开启事务和关闭事务工具
//@Component -->任何地方都能用这个 @Repository //-->这个在Dao层中使用 public class UserDao { public void save() { System.out.println("开始事务"); System.out.println("DB:保存用户"); System.out.println("关闭事务"); } }
//@Component -->任何地方都能用这个 @Repository //-->这个在Dao层中使用 public class UserDao { public void save() { begin(); System.out.println("DB:保存用户"); close(); } public void begin() { System.out.println("开始事务"); } public void close() { System.out.println("关闭事务"); } }
public class AOP { public void begin() { System.out.println("开始事务"); } public void close() { System.out.println("关闭事务"); } }
@Repository //-->这个在Dao层中使用 public class UserDao { AOP aop; public void save() { aop.begin(); System.out.println("DB:保存用户"); aop.close(); } }
public class ProxyFactory { //维护目标对象 private static Object target; //维护关键点代码的类 private static AOP aop; public static Object getProxyInstance(Object target_, AOP aop_) { //目标对象和关键点代码的类都是经过外界传递进来 target = target_; aop = aop_; return Proxy.newProxyInstance( target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { aop.begin(); Object returnValue = method.invoke(target, args); aop.close(); return returnValue; } } ); } }
//把该对象加入到容器中 @Component public class AOP { public void begin() { System.out.println("开始事务"); } public void close() { System.out.println("关闭事务"); } }
@Component public class UserDao { public void save() { System.out.println("DB:保存用户"); } }
<?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.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <bean id="proxy" class="aa.ProxyFactory" factory-method="getProxyInstance"> <constructor-arg index="0" ref="userDao"/> <constructor-arg index="1" ref="AOP"/> </bean> <context:component-scan base-package="aa"/> </beans>
测试,获得UserDao对象,调用方法
public class App { public static void main(String[] args) { ApplicationContext ac = new ClassPathXmlApplicationContext("aa/applicationContext.xml"); IUser iUser = (IUser) ac.getBean("proxy"); iUser.save(); } }
上面使用的是工厂静态方法来建立代理类对象。咱们也使用一下非静态的工厂方法建立对象。
package aa; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; /** * Created by ozc on 2017/5/11. */ public class ProxyFactory { public Object getProxyInstance(final Object target_, final AOP aop_) { //目标对象和关键点代码的类都是经过外界传递进来 return Proxy.newProxyInstance( target_.getClass().getClassLoader(), target_.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { aop_.begin(); Object returnValue = method.invoke(target_, args); aop_.close(); return returnValue; } } ); } }
配置文件:先建立工厂,再建立代理类对象
<?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.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!--建立工厂--> <bean id="factory" class="aa.ProxyFactory"/> <!--经过工厂建立代理--> <bean id="IUser" class="aa.IUser" factory-bean="factory" factory-method="getProxyInstance"> <constructor-arg index="0" ref="userDao"/> <constructor-arg index="1" ref="AOP"/> </bean> <context:component-scan base-package="aa"/> </beans>