1 Spring是什么?
不创建对象,但是描述创建它们的方式。在代码中不直接与对象和服务连接,但在配置文件中描述哪一个组件需要哪一项服务。容器(在 Spring 框架中是 IOC 容器) 负责将这些联系在一起。在典型的 IOC 场景中,容器创建了所有对象,并设置必要的属性将它们连接在一起,决定什么时间调用方法。
具体步骤有:
1、编写业务对象 UserDao UserService 2、配置ApplicationContext.xml 3、实例化Spring IOC 4、通过IOC使用Spring加工过的业务对象 |
以一个实例说明:
1 package com.aop2; 2 3 public interface IMessage { 4 public void check(); 5 }
1 package com.aop2; 2 3 public class Message implements IMessage { 4 5 private String name; 6 7 public String getName() { 8 return name; 9 } 10 11 public void setName(String name) { 12 this.name = name; 13 } 14 15 public void check() { 16 System.out.println("checking " + name); 17 } 18 19 }
配置beans.xml
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xmlns:p="http://www.springframework.org/schema/p" 5 xsi:schemaLocation="http://www.springframework.org/schema/beans 6 http://www.springframework.org/schema/beans/spring-beans-3.1.xsd"> 7 8 <bean id = "message" class = "com.aop2.Message"> 9 <property name = "name" value = "alvin"/> 10 </bean> 11 12 </beans>
添加测试类:
1 package com.aop2; 2 3 import org.junit.Test; 4 import org.springframework.context.ApplicationContext; 5 import org.springframework.context.support.ClassPathXmlApplicationContext; 6 7 public class AopTest { 8 @Test 9 public void test() { 10 ApplicationContext applicationContext = new ClassPathXmlApplicationContext( 11 "com/aop2/beans.xml"); 12 IMessage message1 = (IMessage)applicationContext.getBean("message"); 13 message1.check(); 14 } 15 }
输出:checking alvin
2 通过代理实现
上述过程并没有使用代理机制,下面使用Spring的动态代理机制实现:
更改配置类:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xmlns:p="http://www.springframework.org/schema/p" 5 xsi:schemaLocation="http://www.springframework.org/schema/beans 6 http://www.springframework.org/schema/beans/spring-beans-3.1.xsd"> 7 8 <!-- 配置被代理对象 --> 9 <bean id = "message" class = "com.aop2.Message"> 10 <property name = "name" value = "alvin"/> 11 </bean> 12 13 <!-- 配置代理对象 --> 14 <bean id="proxyFactoryBean" class="org.springframework.aop.framework.ProxyFactoryBean"> 15 <!-- 代理接口集 --> 16 <property name="proxyInterfaces"> 17 <list> 18 <value>com.aop2.IMessage</value> 19 </list> 20 </property> 21 22 <!-- 配置被代理对象 --> 23 <property name="target" ref="message" /> 24 </bean> 25 26 </beans>
修改测试类:
package com.aop2; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class AopTest { @Test public void test() { ApplicationContext applicationContext = new ClassPathXmlApplicationContext( "com/aop2/beans.xml"); IMessage message1 = (IMessage)applicationContext.getBean("proxyFactoryBean"); message1.check(); } }
测试结果:checking alvin
可以看到,测试结果并没有改变,但是我们在beans.xml配置中把被代理对象message利用IOC机制放入代理对象,实现了控制的反转,在测试类中,我们将不再直接取出message类,而是通过调用动态代理类proxyFactoryBean来调用类,并取得类方法。这就揭示了Spring的思想——解耦。它是的类与类之间的耦合度降低,我们不再类中直接调用相应的方法,而是通过bean容器配置,设置必要属性的方法来使用。
3 调用多个接口
增加接口:
1 package com.aop2; 2 3 public interface IMessage2 { 4 public void release(); 5 }
添加property:
1 <property name="proxyInterfaces"> 2 <list> 3 <value>com.aop2.IMessage</value> 4 <value>com.aop2.IMessage2</value> 5 </list> 6 </property>
测试类:
1 package com.aop2; 2 3 import org.junit.Test; 4 import org.springframework.context.ApplicationContext; 5 import org.springframework.context.support.ClassPathXmlApplicationContext; 6 7 public class AopTest { 8 @Test 9 public void test() { 10 ApplicationContext applicationContext = new ClassPathXmlApplicationContext( 11 "com/aop2/beans.xml"); 12 IMessage message1 = (IMessage)applicationContext.getBean("proxyFactoryBean"); 13 IMessage2 message2 = (IMessage2)applicationContext.getBean("proxyFactoryBean"); 14 message1.check(); 15 message2.release(); 16 } 17 }
测试结果为:
checking alvin
release alvin
4 AOP
AOP是在动态代理的基础上实现的,利用InvocationHandler动态代理接口产生一个对象的代理对象,对被代理对象进行代理,以下是动态代理的实质:
1 public class DaiLi_DongTai { 2 public static void main(String[] args) { 3 IGamePlayer player = new GamePlayer("张三"); 4 InvocationHandler handler = new GamePlayIG(player); 5 System.out.println("开始时间:" + new Date()); 6 ClassLoader cl = player.getClass().getClassLoader(); 7 IGamePlayer proxy = (IGamePlayer) Proxy.newProxyInstance(cl, 8 new Class[] { IGamePlayer.class }, handler); 9 proxy.login("zhagnsan", "password"); 10 proxy.killBoss(); 11 proxy.upgrade(); 12 System.out.println("结束时间:" + new Date()); 13 } 14 } 15 16 class GamePlayIG implements InvocationHandler { 17 Class cls = null; //被代理者 18 Object obj = null; //被代理的实例 19 public GamePlayIG(Object obj) {//我要代理谁 20 this.obj = obj; 21 } 22 //调用被代理的方法 23 public Object invoke(Object proxy, Method method, Object[] args) 24 throws Throwable { 25 Object result = method.invoke(this.obj, args); 26 return result; 27 } 28 }
5 AOP实现
加入AOP编程,这里以环绕通知为例,在方法执行的前后加入日志程序。
设定MyMethodInterceptor类:
1 package com.aop2; 2 3 import org.aopalliance.intercept.MethodInterceptor; 4 import org.aopalliance.intercept.MethodInvocation; 5 6 public class MyMethodInterceptor implements MethodInterceptor{ 7 8 public Object invoke(MethodInvocation arg0) throws Throwable { 9 System.out.println("写入日志..."); 10 Object object = arg0.proceed(); 11 System.out.println("日志完成..."); 12 return object; 13 } 14 }
修改beans.xml配置:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xmlns:p="http://www.springframework.org/schema/p" 5 xsi:schemaLocation="http://www.springframework.org/schema/beans 6 http://www.springframework.org/schema/beans/spring-beans-3.1.xsd"> 7 8 <!-- 配置被代理对象 --> 9 <bean id = "message" class = "com.aop2.Message"> 10 <property name = "name" value = "alvin"/> 11 </bean> 12 13 <!-- 配置环绕通知 --> 14 <bean id = "myMethodInterceptor" class = "com.aop2.MyMethodInterceptor"/> 15 16 <!-- 配置代理对象 --> 17 <bean id="proxyFactoryBean" class="org.springframework.aop.framework.ProxyFactoryBean"> 18 <!-- 代理接口集 --> 19 <property name="proxyInterfaces"> 20 <list> 21 <value>com.aop2.IMessage</value> 22 <value>com.aop2.IMessage2</value> 23 </list> 24 </property> 25 26 <!-- 织入通知对象 --> 27 <property name = "interceptorNames"> 28 <list> 29 <value>myMethodInterceptor</value> 30 </list> 31 </property> 32 33 <!-- 配置被代理对象 --> 34 <property name="target" ref="message" /> 35 </bean> 36 37 </beans>
输出为:
写入日志...
checking alvin
日志完成...
写入日志...
release alvin
日志完成...
可以看到,在执行方法的前后,都有通知织入。