(1)Spring IOC原理
IOC的意思是控件反转也就是由容器控制程序之间的关系,把控件权交给了外部容器,之前的写法,由程序代码直接操控,而现在控制权由应用代码中转到了外部容器,控制权的转移是所谓反转。网上有一个很形象的比喻:
我们是如何找女朋友的?常见的情况是,我们到处去看哪里有长得漂亮身材又好的mm,然后打听她们的兴趣爱好、qq号、电话号、ip号、iq号………,想办法认识她们,
投其所好送其所要,然后嘿嘿……这个过程是复杂深奥的,我们必须自己设计和面对每个环节。传统的程序开发也是如此,在一个对象中,如果要使用另外的对象,
就必须得到它(自己new一个,或者从JNDI中查询一个),使用完之后还要将对象销毁(比如Connection等),对象始终会和其他的接口或类藕合起来。
那么IoC是如何做的呢?有点像通过婚介找女朋友,在我和女朋友之间引入了一个第三者:婚姻介绍所。婚介管理了很多男男女女的资料,我可以向婚介提出一个列表,
告诉它我想找个什么样的女朋友,比如长得像李嘉欣,身材像林熙雷,唱歌像周杰伦,速度像卡洛斯,技术像齐达内之类的,然后婚介就会按照我们的要求,提供一个mm,
我们只需要去和她谈恋爱、结婚就行了。简单明了,如果婚介给我们的人选不符合要求,我们就会抛出异常。整个过程不再由我自己控制,而是有婚介这样一个类似容器的
机构来控制。Spring所倡导的开发方式就是如此,所有的类都会在spring容器中登记,告诉spring你是个什么东西,你需要什么东西,然后spring会在系统运行到适当的时候,
把你要的东西主动给你,同时也把你交给其他需要你的东西。所有的类的创建、销毁都由 spring来控制,也就是说控制对象生存周期的不再是引用它的对象,
而是spring。对于某个具体的对象而言,以前是它控制其他对象,现在是所有对象都被spring控制,所以这叫控制反转。
(2)DI(Dependency Injection,依赖注入)
IoC的一个重点是在系统运行中,动态的向某个对象提供它所需要的其他对象。这一点是通过DI(Dependency Injection,
依赖注入)来实现的。比如对象A需要操作数据库,以前我们总是要在A中自己编写代码来获得一个Connection对象,有了
spring我们就只需要告诉spring,A中需要一个Connection,至于这个Connection怎么构造,何时构造,A不需要知道。
在系统运行时,spring会在适当的时候制造一个Connection,然后像打针一样,注射到A当中,这样就完成了对各个对象之间关系
的控制。A需要依赖 Connection才能正常运行,而这个Connection是由spring注入到A中的,依赖注入的名字就这么来的。
下面来模拟下IOC和DI的实现原理。
项目的结构图如下:
1、首先定义DAO接口和接口的实现类
[java] view plaincopy
1. package com.dao;
2.
3. public interface PersonDAO {
4. public void save();
5. }
[java] view plaincopy
1. package com.dao.impl;
2.
3. import com.dao.PersonDAO;
4.
5. public class PersonDaoImpl implements PersonDAO {
6.
7. @Override
8. public void save() {
9. System.out.println("保存");
10. }
11.
12. }
2、创建一个Junit测试类
[java] view plaincopy
1. package com.test;
2.
3. import org.junit.Test;
4. import org.springframework.context.ApplicationContext;
5. import org.springframework.context.support.ClassPathXmlApplicationContext;
6.
7. import com.dao.PersonDAO;
8. import com.myUtil.MyClassPathXmlApplicationContext;
9. import com.service.PersonService;
10.
11.
12. public class PersonTest {
13.
14. @Test
15. public void instanceSpring1(){
16. /**
17. *
18. * spring 的实现
19. */
20. //IOC
21. ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml");
22. PersonDAO pd = (PersonDAO) ac.getBean("personDAO");
23. pd.save();
24. //DI
25. PersonService ps = (PersonService) ac.getBean("personService");
26. ps.save();
27. }
28.
29. @Test
30. public void instanceSpring2(){
31.
32. /**
33. * 我的实现
34. *
35. */
36. MyClassPathXmlApplicationContext mac = new MyClassPathXmlApplicationContext("beans.xml");
37. PersonDAO mpd = (PersonDAO) mac.getBean("personDAO");
38. mpd.save();
39. //DI
40. PersonService ps = (PersonService) mac.getBean("personService");
41. ps.save();
42. }
43.
44. }
方法instanceSpring1为Spring中的实现用到ClassPathXmlApplicationContext类,要实现IOC的原理要定义自己
的MyClassPathXmlApplicationContext首先读出beans.xml中的配置信息,通过反射机制实现bean,最后注入所需要的
bean。
[java] view plaincopy
1. package com.myUtil;
2. import java.beans.Introspector;
3. import java.beans.PropertyDescriptor;
4. import java.lang.reflect.Method;
5. import java.net.URL;
6. import java.util.ArrayList;
7. import java.util.HashMap;
8. import java.util.List;
9. import java.util.Map;
10. import org.dom4j.Document;
11. import org.dom4j.Element;
12. import org.dom4j.io.SAXReader;
13.
14. public class MyClassPathXmlApplicationContext {
15. // xml所有的属性
16. private ArrayList<BeanDefinition> beanDefinitions = new ArrayList<BeanDefinition>();
17. // xml中所有的bean
18. private Map<String, Object> sigletons = new HashMap<String, Object>();
19.
20. public MyClassPathXmlApplicationContext(String file) {
21. readXml(file);
22. instanceBeans();
23. instanceObject();
24. }
25.
26. /**
27. * 注入
28. */
29. private void instanceObject() {
30. for (BeanDefinition beanDefinition : beanDefinitions) {
31. //判断有没有注入属性
32. if (beanDefinition.getProperty() != null) {
33. Object bean = sigletons.get(beanDefinition.getId());
34. if (bean != null) {
35. try {
36. //得到被注入bean的所有的属性
37. PropertyDescriptor[] ps = Introspector.getBeanInfo(bean.getClass()).getPropertyDescriptors();
38. //得到所有的注入bean属性
39. for(PropertyDefinition propertyDefinition:beanDefinition.getProperty()){
40. for(PropertyDescriptor propertyDescriptor:ps){
41. if(propertyDescriptor.getName().equals(propertyDefinition.getName())){
42. Method setter = propertyDescriptor.getWriteMethod();//获取set方法
43. if(setter!=null){
44. setter.setAccessible(true);//得到private权限
45. //注入属性
46. setter.invoke(bean, sigletons.get(propertyDefinition.getRef()));
47. }
48. break;
49. }
50. }
51. }
52. } catch (Exception e) {
53. // TODO Auto-generated catch block
54. e.printStackTrace();
55. }
56. }
57. }
58. }
59. }
60.
61. /**
62. * 实例所有的bean
63. */
64. private void instanceBeans() {
65. for (int i = 0; i < beanDefinitions.size(); i++) {
66. BeanDefinition bd = beanDefinitions.get(i);
67. try {
68. try {
69. if (bd.getClassName() != null
70. && !bd.getClassName().equals(""))
71. sigletons.put(bd.getId(), Class.forName(
72. bd.getClassName()).newInstance());
73. } catch (InstantiationException e) {
74. // TODO Auto-generated catch block
75. e.printStackTrace();
76. } catch (IllegalAccessException e) {
77. // TODO Auto-generated catch block
78. e.printStackTrace();
79. }
80. } catch (ClassNotFoundException e) {
81. // TODO Auto-generated catch block
82. e.printStackTrace();
83. }
84. }
85. }
86.
87. /**
88. * 读xml
89. *
90. * @param file
91. */
92. private void readXml(String file) {
93. try {
94. SAXReader reader = new SAXReader(); // 使用SAX方式解析XML
95. URL xmlPath = this.getClass().getClassLoader().getResource(file);
96. Document doc = reader.read(xmlPath);
97. Element root = doc.getRootElement(); // 取得根节点
98. List<Element> beans = root.elements();
99. for (Element element : beans) {
100. String id = element.attributeValue("id");// id;
101. String clazz = element.attributeValue("class");
102. BeanDefinition bd = new BeanDefinition(id, clazz);
103. // 读取子元素
104. if (element.hasContent()) {
105. List<Element> propertys = element.elements();
106. for (Element property : propertys) {
107. String name = property.attributeValue("name");
108. String ref = property.attributeValue("ref");
109. PropertyDefinition pd = new PropertyDefinition(name,
110. ref);
111. bd.getProperty().add(pd);
112. }
113. }
114. beanDefinitions.add(bd);
115. }
116. } catch (Exception e) {
117. // TODO: handle exception
118. }
119. }
120.
121. /**
122. * 通过名字得到bean
123. *
124. * @param str
125. * @return
126. */
127. public Object getBean(String str) {
128. return sigletons.get(str);
129. }
130.
131. }
读取所的bean实体
[java] view plaincopy
1. package com.myUtil;
2.
3. import java.util.ArrayList;
4. import java.util.List;
5.
6. public class BeanDefinition {
7. private String id;
8. private String className;
9. private List<PropertyDefinition> property = new ArrayList<PropertyDefinition>();
10.
11. public BeanDefinition(String id, String className) {
12. super();
13. this.id = id;
14. this.className = className;
15. }
16.
17. public String getId() {
18. return id;
19. }
20.
21. public void setId(String id) {
22. this.id = id;
23. }
24.
25. public String getClassName() {
26. return className;
27. }
28.
29. public void setClassName(String className) {
30. this.className = className;
31. }
32.
33. public List<PropertyDefinition> getProperty() {
34. return property;
35. }
36.
37. public void setProperty(List<PropertyDefinition> property) {
38. this.property = property;
39. }
40.
41. }
注入属性实体
[java] view plaincopy
1. package com.myUtil;
2.
3. public class PropertyDefinition {
4. private String name;
5. private String ref;
6.
7. public PropertyDefinition(String name, String ref) {
8. this.name = name;
9. this.ref = ref;
10. }
11.
12. public String getName() {
13. return name;
14. }
15.
16. public void setName(String name) {
17. this.name = name;
18. }
19.
20. public String getRef() {
21. return ref;
22. }
23.
24. public void setRef(String ref) {
25. this.ref = ref;
26. }
27.
28. }
业务接口和实现类
[java] view plaincopy
1. package com.service;
2.
3. public interface PersonService {
4. public void save();
5. }
[java] view plaincopy
1. package com.service.impl;
2.
3. import com.dao.PersonDAO;
4. import com.service.PersonService;
5.
6. public class PersonServiceImpl implements PersonService{
7. private PersonDAO pdo;
8.
9. public PersonDAO getPdo() {
10. return pdo;
11. }
12.
13. public void setPdo(PersonDAO pdo) {
14. this.pdo = pdo;
15. }
16.
17. @Override
18. public void save() {
19. pdo.save();
20. }
21.
22. }
beans.xml配置
[java] view plaincopy
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. xsi:schemaLocation="http://www.springframework.org/schema/beans
5. http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
6.
7. <bean id="personDAO" class="com.dao.impl.PersonDaoImpl"></bean>
8. <bean id="personService" class="com.service.impl.PersonServiceImpl">
9. <property name="pdo" ref="personDAO"></property>
10. </bean>
11. </beans>
(3)AOP面向切面
AOP是OOP的延续,是(Aspect Oriented Programming)的缩写,意思是面向切面编程。要理解AOP首先得弄明白代理的概念。对于代理看下点击打开链接这篇文章。
AOP(Aspect Orient Programming),作为面向对象编程的一种补充,广泛应用于处理一些具有横切性质的系统级服务,如事务管理、安全检查、缓存、对象池管理等。 AOP 实现的关键就在于 AOP 框架自动创建的 AOP 代理,AOP 代理则可分为静态代理和动态代理两大类,其中静态代理是指使用 AOP 框架提供的命令进行编译,从而在编译阶段就可生成 AOP 代理类,因此也称为编译时增强;而动态代理则在运行时借助于 JDK 动态代理、CGLIB 等在内存中"临时"生成 AOP 动态代理类,因此也被称为运行时增强。
知道这些其他的就是些配置了。
简单的实现annotations和xml对AOP的实现。
首先看下目录结构
MyInterceptor、MyInterceptor2分别是以annotations和xml定义的切面类
[java] view
plaincopy
1.
package com.service;
2.
3.
import org.aspectj.lang.annotation.Aspect;
4.
import org.aspectj.lang.annotation.Before;
5.
import org.aspectj.lang.annotation.Pointcut;
6.
7.
@Aspect
8.
public class MyInterceptor {
9.
@Pointcut("execution (* com.serviceImpl.PersonServiceImpl.*(..))")
10.
private void myMethod(){};
11.
12.
@Before("myMethod()")
13.
public void doAccessCheck(){
14.
System.out.println("before");
15.
}
16.
17.
}
[java] view
plaincopy
1.
package com.service;
2.
3.
public class MyInterceptor2 {
4.
public void doAccessCheck(){
5.
System.out.println("before");
6.
}
7.
}
业务和接口
[java] view
plaincopy
1.
package com.service;
2.
3.
public interface PersonService {
4.
public void save(String name);
5.
public void update(String name);
6.
}
[java] view
plaincopy
1.
package com.serviceImpl;
2.
3.
import com.service.PersonService;
4.
5.
public class PersonServiceImpl implements PersonService {
6.
7.
@Override
8.
public void save(String name) {
9.
// TODO Auto-generated method stub
10.
System.out.println("保存");
11.
}
12.
13.
@Override
14.
public void update(String name) {
15.
// TODO Auto-generated method stub
16.
System.out.println("修改");
17.
}
18.
19.
}
简单做个方法前通知,其他的都一样。
[java] view
plaincopy
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" xmlns:aop="http://www.springframework.org/schema/aop"
4.
xsi:schemaLocation="http://www.springframework.org/schema/beans
5.
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
6.
http://www.springframework.org/schema/aop
7.
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
8.
9.
<aop:aspectj-autoproxy/>
10.
11.
<bean id="personServiceImpl" class="com.serviceImpl.PersonServiceImpl"></bean>
12.
<bean id="personInterceptor" class="com.service.MyInterceptor2"></bean>
13.
14.
<aop:config>
15.
<aop:aspect id="asp" ref="personInterceptor">
16.
<aop:pointcut id="myCut" expression="execution (* com.serviceImpl.PersonServiceImpl.*(..))"/>
17.
<aop:before pointcut-ref="myCut" method="doAccessCheck"/>
18.
</aop:aspect>
19.
</aop:config>
20.
</beans>
测试类
[java] view
plaincopy
1.
package com.test;
2.
3.
4.
5.
import org.junit.Test;
6.
import org.springframework.context.ApplicationContext;
7.
import org.springframework.context.support.ClassPathXmlApplicationContext;
8.
9.
import com.service.PersonService;
10.
11.
public class AopTest {
12.
13.
@Test
14.
public void interceptorTest(){
15.
ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml");
16.
PersonService ps = (PersonService) ac.getBean("personServiceImpl");
17.
ps.save("aa");
18.
}
19.
}