ICO工厂产生对象的方法:
解析方式为DOM4J的解析方式,需要导入相应的架包
通过方式得到实体类的对象,然后通过method的invoke方法给属性赋值,具体的实现工厂为:
/**
* 模拟ioc实例化对象的思路
* 1.xml解析
* 2.对象实例化
* 3.对外提供getObj方法
* 根据对象名获取value
* 4.给属性赋值(依赖注入|装配)
* 反射实现 set 方法赋值操作
*
*/
public class SxtFactory_07 implements SxtFactory {
private Map map=new HashMap();
private List beans =new ArrayList();
public SxtFactory_07(String fileName) {
this.parseXml(fileName);
this.instanceBean();
this.setSxtProperty();
}
/**
* 给属性赋值
*/
private void setSxtProperty() {
try {
if(beans.size()>0){
for(SxtBean sxtBean:beans){
// 获取属性集合
List properties=sxtBean.getProperties();
if(null !=properties && properties.size()>0){
for(SxtProperty property:properties){
String id=property.getId();
// 首字母大写
id=id.toUpperCase().charAt(0)+id.substring(1);
String ref=property.getRef();
Class clazz=map.get(sxtBean.getId()).getClass();
Method method= clazz.getDeclaredMethod("set"+id,map.get(ref).getClass());
method.invoke(map.get(sxtBean.getId()),map.get(ref));
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
private void instanceBean() {
try {
if(beans.size()>0){
for(SxtBean sxtBean:beans){
map.put(sxtBean.getId(),Class.forName(sxtBean.getClazz()).newInstance());
}
}
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
/**
* xml 解析
* @param fileName
*/
private void parseXml(String fileName) {
/**
* xml 解析
*/
URL url= this.getClass().getClassLoader().getResource(fileName);
if(null !=url){
SAXReader saxReader=new SAXReader();
try {
Document document= saxReader.read(url);
XPath xPath= document.createXPath("beans/bean");
List elements= xPath.selectNodes(document);
if(null!=elements && elements.size()>0){
for(Element element:elements){
xPath=document.createXPath("property");
// 匹配当前的元素
List subElements= xPath.selectNodes(element);
List properties=null;
SxtBean sxtBean= new SxtBean(element.attributeValue("id"),element.attributeValue("class"));
if(null !=subElements && subElements.size()>0){
properties=new ArrayList();
for(Element subElement:subElements){
SxtProperty property=new SxtProperty(subElement.attributeValue("id"),subElement.attributeValue("ref"));
properties.add(property);
}
sxtBean.setProperties(properties);
}
beans.add(sxtBean);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}else{
System.out.println("文件未找到!!!");
}
}
@Override
public Object getObj(String name) {
return map.get(name);
}
}
spring.xml文件
1.获取扫描包的范围
com.shsxt02(直接给的的方式)
2.获取指定包以及子包下的所有的class 文件(不考虑jar包)
C:\\java\workspace21\\ioc01\\src\main\\java\\com\\shsxt02\\dao\\UserDao.class
C:\\java\workspace21\\ioc01\\src\main\\java\\com\\shsxt02\\dao\\AccountDao.class
.....
/**
* @Description:获取指定包以及子包下的所有的class 文件(不考虑jar包)
* @Author: Mr Tong
* @Date: 2018/9/26 21:48
*/
public static void getAllClass(String pkg){
// com/shsxt02
URL url=Thread.currentThread().getContextClassLoader().getResource(replacePath(pkg));
String basePath=url.getFile();
String[] subFileStrs= new File(basePath).list();
for(String str:subFileStrs){
// 获取子目录地址
String subFilePath=basePath+"/"+str;
File subFile=new File(subFilePath);
if(subFile.isDirectory()){
getAllClass(pkg+"."+subFile.getName());
}else{
//System.out.println(basePath+"/"+subFile.getName());
// com.shsxt02.controller.UserController
// 存储包名-指定类的全路径
clazzzz.add(pkg+"."+subFile.getName());
}
}
}
3.判断class 类级别上有没有标注指定注解
注解存在
实例化该对象:获取id 唯一标识
/**
* @Description: 实例化对象的方法,
* 判断class 类级别上有没有标注指定注解
* 注解存在:
* 实例化该对象:获取id 唯一标识
* @Author: Mr Tong
* @Date: 2018/9/26 21:47
*/
private static void instanceBeans() {
try {
if(clazzzz.size()>0){
for(String classStr:clazzzz){
classStr=classStr.replace(".class","");
SxtComponent sxtComponent= Class.forName(classStr).getAnnotation(SxtComponent.class);
if(null !=sxtComponent){
Object obj=Class.forName(classStr.replace(".class","")).newInstance();
classStr= classStr.substring(classStr.lastIndexOf(".")+1);
String key=classStr.toLowerCase().charAt(0)+classStr.substring(1);
System.out.println(key);
map.put(key, obj);
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
4.依赖注入
* 获取map 中每个对象的 fields
* 获取字段级别的注解 SxtResource
* 调用field 的set方法实现注入
/**
* 依赖注入
* 获取map 中每个对象的 fields
* 获取字段级别的注解 SxtResource
* 调用field 的set方法实现注入
*/
private static void execAutoWired() {
try {
if(null != map && !(map.isEmpty())){
for(Map.Entry entry:map.entrySet()){
Class clazz = entry.getValue().getClass();
Field[] fields = clazz.getDeclaredFields();
System.out.println(fields + "~~~");
if(null != fields && fields.length>0){
for(Field field:fields){
//SxtComponent sxtComponent= Class.forName(classStr).getAnnotation(SxtComponent.class);
SxtAutoWired sxtAutoWired = field.getAnnotation(SxtAutoWired.class);
System.out.println("sxtAutoWired");
if(null != sxtAutoWired){
field.setAccessible(true);
//field.set(entry.getValue(),map.get(sxtAutoWired.value()));
}
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
对于 bean 的注入,除了使用 xml 配置以外,注解的配置简化开发的速度,使程序看上去更简洁。对于注解的解释, spring 对于注解有专门的解释器,对定义的注解进行解析,实现对应 bean 对象的注入, 反射技术实现。
1.加入 spring-aop jar 包 spring-aop-4.3.2.RELEASE.jar
2.Xml 配置: 加入 context 命名空间 和 xsd 地址
3. 添加
@Autowired 属性字段或 set 方法上
@Resource 属性字段上或 set 方法上
区别: @Autowired 默认按 bean 的类型匹配 可以修改 按名称匹配 和@Qualifier 配合使用
@Resource 默认按名称进行装配,名称可以通过 name 属性进行指定,如果没有指定 name 属性,当注解写在字段上时,默认取字段名进行匹配注入,如果注解写在 setter 方法上默认取属性名进行装配。当找不到与名称匹配的 bean时才按照类型进行装配。 但是需注意的是,如果 name 属性一旦指定,就只会按照名称进行装配。
推荐使用@Resource 注解是属于 J2EE 的,减少了与 spring 的耦合。
实际的开发中, bean 的数量非常多,采用手动配置 bean 的方式已无法满足生产需要, spring 这时候同样提供了扫描的方式,对扫描到的 bean 对象统一进行管理,简化开发配置,提高开发效率。
扫描指定的包:
开发中建议(开发中的一种约定)
@Resource后面没有任何内容,默认通过name属性去匹配bean,找不到再按type去匹配指定了name或者type则根据指定的类型去匹配bean,指定了name和type则根据指定的name和type去匹配bean,任何一个不匹配都将报错