1、@Resource註解原理java
@Resource能夠標註在字段或屬性的setter方法上spring
1. 若是指定了name屬性, 那麼就按name屬性的名稱裝配; apache
2. 若是沒有指定name屬性, 那就按照默認的名稱查找依賴對象;dom
3. 若是按默認名稱查找不到依賴對象, 那麼@Resource註解就會回退到按類型裝配;測試
① 先寫一個本身的@MyResource:ui
import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.lang.annotation.ElementType; @Retention(RetentionPolicy.RUNTIME) // 指定註解保留的範圍 (運行期) @Target({ ElementType.FIELD, ElementType.METHOD }) // 容許註解標註的位置 (屬性, 方法) public @interface MyResource { public String name() default ""; // 提供name屬性 }
② Spring Bean Factory: ClassPathXMLApplicationContextthis
import java.beans.Introspector; import java.beans.PropertyDescriptor; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.net.URL; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.commons.beanutils.ConvertUtils; import org.dom4j.Document; import org.dom4j.Element; import org.dom4j.XPath; import org.dom4j.io.SAXReader; /** * Spring Bean Factory */ public class ClassPathXMLApplicationContext { private List<BeanDefinition> beanDefines = new ArrayList<BeanDefinition>(); private Map<String, Object> sigletons = new HashMap<String, Object>(); public ClassPathXMLApplicationContext(String filename) { this.readXML(filename); this.instanceBeans(); this.annotationInject(); this.injectObject(); } /** * 經過註解實現注入依賴對象 */ private void annotationInject() { for (String beanName : sigletons.keySet()) { // 循環全部的Bean對象 Object bean = sigletons.get(beanName); if (bean != null) { try { // 查找屬性的setter上是否有註解 PropertyDescriptor[] ps = Introspector.getBeanInfo(bean.getClass()).getPropertyDescriptors(); for (PropertyDescriptor properdesc : ps) { // 循環全部屬性 Method setter = properdesc.getWriteMethod();// 獲取屬性的setter方法 if (setter != null && setter.isAnnotationPresent(MyResource.class)) { // 判斷MyResource註解是否存在 MyResource resource = setter.getAnnotation(MyResource.class); Object injectBean = null; if (resource.name() != null && !"".equals(resource.name())) { injectBean = sigletons.get(resource.name()); // 經過MyResource註解的name屬性獲取Bean } else { injectBean = sigletons.get(properdesc.getName()); if (injectBean == null) { // 沒有指定name屬性, 根據屬性名稱進行尋找 for (String key : sigletons.keySet()) { // 根據屬性類型進行尋找 if (properdesc.getPropertyType().isAssignableFrom(sigletons.get(key).getClass())) { injectBean = sigletons.get(key); break; } } } } setter.setAccessible(true); setter.invoke(bean, injectBean);// 把引用對象注入到屬性 } } // 查找字段上是否有註解 Field[] fields = bean.getClass().getDeclaredFields(); // 取得聲明的全部字段 for (Field field : fields) { if (field.isAnnotationPresent(MyResource.class)) { // 判斷字段上是否存在MyResource註解 MyResource resource = field.getAnnotation(MyResource.class); Object value = null; if (resource.name() != null && !"".equals(resource.name())) { // 判斷是否指定name屬性 value = sigletons.get(resource.name()); } else { value = sigletons.get(field.getName()); // 沒有指定name屬性,那麼根據字段名稱尋找 if (value == null) { for (String key : sigletons.keySet()) { // 根據字段類型進行尋找 if (field.getType().isAssignableFrom(sigletons.get(key).getClass())) { value = sigletons.get(key); break; } } } } field.setAccessible(true);// 容許訪問private字段 field.set(bean, value); } } } catch (Exception e) { e.printStackTrace(); } } } } /** * 爲bean對象的屬性注入值 */ private void injectObject() { for (BeanDefinition beanDefinition : beanDefines) { Object bean = sigletons.get(beanDefinition.getId()); if (bean != null) { try { PropertyDescriptor[] ps = Introspector.getBeanInfo(bean.getClass()).getPropertyDescriptors(); for (PropertyDefinition propertyDefinition : beanDefinition.getPropertys()) { for (PropertyDescriptor properdesc : ps) { if (propertyDefinition.getName().equals(properdesc.getName())) { Method setter = properdesc.getWriteMethod(); // 獲取屬性的setter方法 if (setter != null) { Object injectBean = null; if (propertyDefinition.getRef() != null && !"".equals(propertyDefinition.getRef().trim())) { injectBean = sigletons.get(propertyDefinition.getRef()); } else { injectBean = ConvertUtils.convert(propertyDefinition.getValue(), properdesc.getPropertyType()); } setter.setAccessible(true); // private method setter.invoke(bean, injectBean); // 把引用對象注入到屬性 } break; } } } } catch (Exception e) { e.printStackTrace(); } } } } /** * 完成bean的實例化 */ private void instanceBeans() { for (BeanDefinition beanDefinition : beanDefines) { try { if (beanDefinition.getClassName() != null && !"".equals(beanDefinition.getClassName().trim())) sigletons.put(beanDefinition.getId(), Class.forName(beanDefinition.getClassName()).newInstance()); } catch (Exception e) { e.printStackTrace(); } } } /** * 讀取xml配置文件 * * @param filename */ private void readXML(String filename) { SAXReader saxReader = new SAXReader(); Document document = null; try { URL xmlpath = this.getClass().getClassLoader().getResource(filename); document = saxReader.read(xmlpath); Map<String, String> nsMap = new HashMap<String, String>(); nsMap.put("ns", "http://www.springframework.org/schema/beans");// 加入命名空間 XPath xsub = document.createXPath("//ns:beans/ns:bean");// 建立beans/bean查詢路徑 xsub.setNamespaceURIs(nsMap);// 設置命名空間 List<Element> beans = xsub.selectNodes(document);// 獲取文檔下全部bean節點 for (Element element : beans) { String id = element.attributeValue("id");// 獲取id屬性值 String clazz = element.attributeValue("class"); // 獲取class屬性值 BeanDefinition beanDefine = new BeanDefinition(id, clazz); XPath propertysub = element.createXPath("ns:property"); propertysub.setNamespaceURIs(nsMap);// 設置命名空間 List<Element> propertys = propertysub.selectNodes(element); for (Element property : propertys) { String propertyName = property.attributeValue("name"); String propertyRef = property.attributeValue("ref"); String propertyValue = property.attributeValue("value"); PropertyDefinition propertyDefinition = new PropertyDefinition(propertyName, propertyRef, propertyValue); beanDefine.getPropertys().add(propertyDefinition); } beanDefines.add(beanDefine); } } catch (Exception e) { e.printStackTrace(); } } /** * 獲取bean實例 * * @param beanName * @return */ public Object getBean(String beanName) { return this.sigletons.get(beanName); } }
③ beans.xmlspa
<?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:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd"> <context:annotation-config /> <bean id="personDao" class="com.zdp.dao.impl.PersonDaoImpl" /> <bean id="personService" class="com.zdp.service.impl.PersonServiceImpl" /> </beans>
④ PersonServiceImpl.net
import com.zdp.dao.PersonDao; import com.zdp.myspring.MyResource; import com.zdp.service.PersonService; public class PersonServiceImpl implements PersonService { private PersonDao personDao; @MyResource(name="personDao") public void setPersonDao(PersonDao personDao) { this.personDao = personDao; } public void save() { personDao.save(); } }
⑤ 測試一下code
import org.junit.Test; import com.zdp.service.PersonService; import com.zdp.myspring.ClassPathXMLApplicationContext; public class PersonServiceImplTest { @Test public void testSave() { ClassPathXMLApplicationContext ctx = new ClassPathXMLApplicationContext("beans.xml"); PersonService personService = (PersonService)ctx.getBean("personService"); personService.save(); } }
2、spring註解注入
① 引入common-annotations.jar
② 在xml中作以下配置:
<?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:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd"> <context:annotation-config /> </beans>
③ 在Java代碼中使用@Autowired或@Resource註解方式進行裝配
兩者區別: @Autowired默認按類型裝配, @Resource默認按名稱裝配, 當找不到與名稱匹配的Bean纔會按類型匹配.
@Resource // 配置在屬性上 private PersonDao personDao;
@Resource(name="personDao") // 名稱經過@Resource的name屬性指定 private PersonDao personDao;
@Resource // 配置在setter方法上 public void setPersonDao(PersonDao personDao) { this.personDao = personDao; }
@Autowired註解是按類型裝配依賴對象, 默認狀況下它要求依賴對象必須存在,
若是容許null值, 能夠設置required=false
若是想使用按名稱裝配, 能夠結合@Qualifier註解一塊兒使用
@Autowired @Qualifier("personDao") private PersonDao personDao
3、spring自動掃描和管理Bean
前面的例子都是使用xml的bean定義來配置組件, 在一個稍大的項目中, 一般會有上百個組件, 若是這些組件都採用xml的bean定義來配置, 顯然會增長配置文件的體積, 查找及維護起來也不太方便.
spring2.5爲咱們引入了組件自動掃描機制, 它能夠在類路徑下尋找標註了@Component、@Controller、@Service、@Reponsitory註解的類, 並把這些類歸入進spring容器中管理. 它的做用和在xml中使用bean節點配置組件是同樣的.
① beans.xml
<?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:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd"> <context:component-scan base-package="com.zdp"/> <!-- base-package爲須要掃描的包(含子包) --> </beans>
② PersonServiceImpl
@Service("personService") @Scope("singleton") public class PersonServiceImpl implements PersonService { private PersonDao personDao; @Resource(name="personDao") public void setPersonDao(PersonDao personDao) { this.personDao = personDao; } @PostConstruct public void init(){ System.out.println("init.."); } @PreDestroy public void destory(){ System.out.println("destory.."); } public void save() { personDao.save(); } }
@Controller一般用於標註控制層組件(如struts中的action);
@Service一般用於標註業務層組件;
@Repository一般用於標註數據訪問組件, 即DAO組件;
@Component泛指組件, 當組件很差歸類的時候, 咱們可使用這個註解進行標註;