Bean基于XML和基于注解的装配

一、Bean基于XML的装配

1.生命周期接着day01_1来讲(了解)

Bean生命周期的如图所示:用红色框起来的都是我们要研究的!

如图Bean is Ready To User 是bean实例的使用,当bean调用方法时会先调用初始化方法,在初始化方法前后又有两个方法分别是:预初始化方法,后初始化方法。当IOC容器关闭时将会自动调用销毁方法。

2.介绍初始和销毁方法

spring关于初始化和销毁方法的使用格式如下:前提你需要在配置的bean里面写入你想要初始化和销毁的代码

<bean id="" class="" init-method="初始化方法名称"  destroy-method="销毁的方法名称">

spring配置如下:

<bean id="userService" class="cn.itcast.b_bean_xml.d_lifecycle.UserServiceImpl" init-method="myInit" destroy-method="myDestory"></bean>

关于配置bean的代码如下:配置了初始化方法和销毁方法

public class UserServiceImpl implements UserService {

    public void addUser() {
System.out.println("添加用户成功!!!"); } public void myInit(){
System.out.println("初始化方法执行了"); }
public void myDestory(){
System.out.println("销毁方法执行了");
}
}

关于测试类的代码如下:

    @Test
public void fun01()throws Exception {//测试初始化方法和销毁方法
String xmlPath = "cn/itcast/b_bean_xml/d_lifecycle/applicationContext.xml";
ClassPathXmlApplicationContext applicationContext =new ClassPathXmlApplicationContext(xmlPath);
//使用默认构造创建的实例
UserService userService=(UserService) applicationContext.getBean("userService");//填写id名称
UserService userService2=(UserService) applicationContext.getBean("userService");
//默认是单例的
System.out.println(userService==userService2);
userService.addUser();
//关闭IOC容器时才会执行销毁方法,我们可以通过反射调用close但是没这个必要
//applicationContext.getClass().getMethod("close").invoke(applicationContext);这说明实现类含有close方法
applicationContext.close();
}

3. BeanPostProcessor 后处理Bean  

①  spring 提供一种机制,只要实现此接口BeanPostProcessor,并将实现类提供给spring容器,spring容器将自动执行,在初始化方法前执行before(),在初始化方法后执行after() 。 配置<bean class="">

②关于BeanPostProcessor接口的api解释如下:

Factory hook(勾子) that allows for custom modification of new bean instances, e.g. checking for marker interfaces or wrapping them with proxies.

这个接口是spring提供工厂勾子,用于修改实例对象,可以生成代理对象,是AOP底层。

提供的这两个接口我们可以创建一个实现类来实现这两个方法,这个两个方法会将spring创建的bean进行包装在初始化方法前后执行如上面生命周期过程可知。

模拟spring所进行的过程:

A a =new A();
a = B.before(a) //返回一个包装bean --> 将a的实例对象传递给后处理bean,可以生成代理对象并返回。
a.init();
a = B.after(a);//返回出一个包装bean a.addUser(); //生成代理对象,目的在目标方法前后执行(例如:开启事务、提交事务) a.destroy()

关于上面的接口来实现上面的过程

BeanPostProcessor实现类:spring会自动去调用实现该接口的的实现类,并会将创建好的bean传进这个这个类的两个方法里面实现包装增强后返回

 public class MyBeanPostprocessor implements BeanPostProcessor {

     /*
* 在spring里面做了这样一件事当你在spring里面装配了<bean class="cn.itcast.b_bean_xml.f_lifecycle.MyBeanPostprocessor"></bean>
* 它会检查你放入IOC容器中的这个类是不是BeanPostProcessor的实现类 如果不是则不会走前后初始化方法,如果是就会进行下面操作
* A a =new A(); //spring会首先创建实例
* a = B.before(a) --> 将a的实例对象传递给后处理bean,可以生成代理对象并返回。
* a.init();代理对象调用初始化方法
* a = B.after(a);将代理对象再放入后初始化方法又会返回一个代理对象
* a.addUser(); //生成代理对象,目的在目标方法前后执行(例如:开启事务、提交事务)
* a.destroy()
*
*/
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
System.out.println("前处理方法" + beanName);
return bean;
} public Object postProcessAfterInitialization(final Object bean, String beanName)
throws BeansException {
System.out.println("后处理方法" + beanName); Object obj =Proxy.newProxyInstance(this.getClass().getClassLoader(),bean.getClass().getInterfaces(), new InvocationHandler() { public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("开启事务......");
Object obj = method.invoke(bean,args);
System.out.println("提交事务......");
return obj;
}
} );
return obj;
} }

BeanPostprocessor的实现类MyBeanPostprocessor

需要将这个接口的实现类装入IOC容器这样spring才能调用:

<bean class="cn.itcast.b_bean_xml.f_lifecycle.MyBeanPostprocessor"></bean>
<bean id="userService" class="cn.itcast.b_bean_xml.f_lifecycle.UserServiceImpl" init-method="myInit" destroy-method="myDestory"></bean>

需要包装的bean代码为:

 package cn.itcast.b_bean_xml.f_lifecycle;

 public class UserServiceImpl implements UserService {

     public void addUser() {
System.out.println("添加用户成功!!!"); } public void myInit(){
System.out.println("初始化方法执行了"); }
public void myDestory(){
System.out.println("销毁方法执行了");
}
}

需要包装的bean类

问题1:后处理bean作用某一个目标类,还是所有目标类?

所有

问题2:如何只作用一个?

通过“参数2”beanName进行控制

4.关于bean属性的属性依赖注入

①依赖注入方式:手动装配 和 自动装配

②属性手动依赖注入有两种基于:一般进行配置信息都采用手动 基于xml装配:构造方法、setter方法  基于注解装配:在注解里面注入value的值

构造方法注入的方式:需要给有参数的构造函数类

spring的配置如下:

 <!--在bean里面有一个子元素 constructor-arg 是手动装配的一种 叫做构造方法注入 其中
index:代表构造函数中参数的索引值,而且这个index会默认匹配第一个构造函数 如果想指定准确用type和index一起指定
type:表示构造函数中参数的类型
constructor-arg元素的个数代表配配多少个参数的构造函数
--> <bean id="user" class="cn.itcast.c_bean_xml.a_constructInject.User">
<constructor-arg index="0" type="Integer" value="2"></constructor-arg>
<constructor-arg index="1" type="String" value="1"></constructor-arg>
</bean>

给定的类代码为:

 public class User {
private Integer uid;
private String name;
private Integer age; public User(Integer uid,String name) {
super();
this.uid = uid;
this.name=name;
} public User(String name, Integer age) {
super();
this.name = name;
this.age = age;
} public Integer getUid() {
return uid;
}
public void setUid(Integer uid) {
this.uid = uid;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
} @Override
public String toString() {
return "User [uid=" + uid + ", name=" + name + ", age=" + age + "]";
} }

给定的类

测试代码:

public class Test01 {
@Test
public void fun01()throws Exception {//测试初始化方法和销毁方法
String xmlPath = "cn/itcast/c_bean_xml/a_constructInject/applicationContext.xml";
ApplicationContext applicationContext =new ClassPathXmlApplicationContext(xmlPath); User user=(User) applicationContext.getBean("user");//填写id名称
System.out.println(user);
} }

使用setter方式注入:需要给属性提供setter方法

spring配置如下:

 <!-- setter方法注入
* 普通数据
<property name="" value="值">
等效
<property name="">
<value>值
* 引用数据
<property name="" ref="另一个bean">
等效
<property name="">
<ref bean="另一个bean"/>
--> <bean id="person" class="cn.itcast.c_bean_xml.b_setterInject.Person">
<property name="name" value="小西西"></property>
<property name="age" value="20"></property>
<property name="homeAddress" ref="homeAddress"></property>
<property name="companyAddress"><ref bean="companyAddress"/></property>
</bean> <bean id="homeAddress" class="cn.itcast.c_bean_xml.b_setterInject.Address">
<property name="addr"><value>武汉职业技术学院</value></property>
<property name="tel" value="123456"></property>
</bean> <bean id="companyAddress" class="cn.itcast.c_bean_xml.b_setterInject.Address">
<property name="addr"><value>武汉轻工大学</value></property>
<property name="tel"><value>12138</value></property>
</bean>

spring的配置文件

给定的类代码如下:

 public class Person {
private String name;
private Integer age;
private Address homeAddress;
private Address companyAddress;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Address getHomeAddress() {
return homeAddress;
}
public void setHomeAddress(Address homeAddress) {
this.homeAddress = homeAddress;
}
public Address getCompanyAddress() {
return companyAddress;
}
public void setCompanyAddress(Address companyAddress) {
this.companyAddress = companyAddress;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + ", homeAddress="
+ homeAddress + ", companyAddress=" + companyAddress + "]";
} }

Person类

 public class Address {
private String addr;
private String tel; public String getAddr() {
return addr;
}
public void setAddr(String addr) {
this.addr = addr;
}
public String getTel() {
return tel;
}
public void setTel(String tel) {
this.tel = tel;
}
@Override
public String toString() {
return "Address [addr=" + addr + ", tel=" + tel + "]";
} }

Address类

测试代码如下:

 public class Test01 {
@Test
public void fun01() {//测试初始化方法和销毁方法
String xmlPath = "cn/itcast/c_bean_xml/b_setterInject/applicationContext.xml";//给定xml文件路径
ApplicationContext applicationContext =new ClassPathXmlApplicationContext(xmlPath);//加载spring配置文件 Person person=(Person) applicationContext.getBean("person");//填写id名称,使用IOC容器得到实例
System.out.println(person); } }

测试代码

③自动装配:struts和spring 整合可以自动装配byType:按类型装配byName:按名称装配constructor构造装配, auto:不确定装配。

5.P命名空间(l了解)

①什么是P命名空间:p命名空间是用来简化setter注入的,替换<property name="属性名">,而是在 <bean p:属性名="普通值"  p:属性名-ref="引用值">

②使用的前提是要加上命名空间

spring的配置文件如下:效果和上面的setter方式注入效果一样

 <bean id="person" class="cn.itcast.c_bean_xml.c_p_space.Person"
p:name="小君君" p:age="20" p:companyAddress-ref="companyAddress" p:homeAddress-ref="homeAddress" >
</bean> <bean id="homeAddress" class="cn.itcast.c_bean_xml.c_p_space.Address" p:addr="武汉职业技术学院" p:tel="123138">
</bean> <bean id="companyAddress" class="cn.itcast.c_bean_xml.c_p_space.Address" p:addr="武汉轻工大学" p:tel="12138">
</bean>

spring的配置文件

6.SpEL表达式(了解)

①什么是SpEL:SpEL是spring自己的一套表达式这个表达式也可以简化setter注入,使setter注入变得更加灵活

对<property>进行统一编程,所有的内容都使用value

<property name="" value="#{表达式}">

#{123}、#{'jack'} : 数字、字符串

#{beanId} :另一个bean引用

#{beanId.propName} :操作数据

#{beanId.toString()} :执行方法

#{T(类).字段|方法} :静态方法或字段

spring配置文件如下:

 <!--SpEL表达式也是用来简化 setter注入的
使格式都变为<property name="" value="">
<property name="cname" value="#{'jack'}"></property>这个是给实例注入赋值
<property name="cname" value="#{customer.cname}"></property>这个是的当属性有默认值时调用属性再注入进去(没人这么干多此一举但是我们要知道可以调用实例的属性值)
<property name="cname" value="#{customer.cname.toUpperCase()}"></property>我们可以调用方法进行操作和OGNL表达式有点像,但是这种方式如果没有默认值程序就会报控指针了
<property name="cname" value="#{customer.cname?.toUpperCase()}"></property>对引用类型的对象前加一个?判断是否是null如果是null则这个值就为null程序还是能走下去
格式:#{T(类).静态方法|字段}
<property name="pi" value="#{T(Math).PI}"></property>调用静态常量值赋值
-->
<bean id="customer" class="cn.itcast.c_bean_xml.d_SPEL.Customer">
<property name="cname" value="#{customer.cname?.toUpperCase()}"></property>
<property name="pi" value="#{T(Math).PI}"></property>
</bean>
</beans>

spring配置文件关于SpEL

给定的类:

 public class Customer {
private String cname="jack";
private Double pi; //Math.PI;
public String getCname() {
return cname;
}
public void setCname(String cname) {
this.cname = cname;
}
public Double getPi() {
return pi;
}
public void setPi(Double pi) {
this.pi = pi;
}
@Override
public String toString() {
return "Customer [cname=" + cname + ", pi=" + pi + "]";
} }

给定的类

测试代码:

 public class Test01 {
@Test
public void fun01() {//测试初始化方法和销毁方法
String xmlPath = "cn/itcast/c_bean_xml/d_SPEL/applicationContext.xml";//给定xml文件路径
ApplicationContext applicationContext =new ClassPathXmlApplicationContext(xmlPath);//加载spring配置文件 Customer customer=(Customer) applicationContext.getBean("customer");//填写id名称,使用IOC容器得到实例
System.out.println(customer); } }

测试代码

7.注入集合的方式:

一个类的属性是集合如何在配置文件中为这个集合赋值

spring配置文件代码如下:按照下面的方式来注入集合

 <!--
集合的注入都是给<property>添加子标签
数组:<array>
List:<list>
Set:<set>
Map:<map> ,map存放k/v 键值对,使用<entry>描述
Properties:<props> <prop key=""></prop> 【】 普通数据:<value>
引用数据:<ref>
--> <bean id="collectionData" class="cn.itcast.c_bean_xml.e_arry_collection_Map.CollectionData">
<property name="arrayData">
<array>
<value>张三</value>
<value>李四</value>
</array>
</property>
<property name="listData">
<list>
<value>王五</value>
<value>赵六</value>
</list>
</property> <property name="setData">
<set>
<value>小君君</value>
<value>小西西</value>
</set>
</property> <property name="mapData">
<map>
<entry key="Jack" value="杰克"></entry>
<entry>
<key><value>rose</value></key>
<value>肉丝</value>
</entry>
</map>
</property> <property name="propertiesData">
<props>
<prop key="高富帅">富</prop>
<prop key="白富美">美</prop>
</props> </property>
</bean>

注入集合的spring配置文件

给定的类:类里面的属性包含集合

 public class CollectionData {
private String[] arrayData;
private List<String> listData;
private Set<String> setData;
private Map<String,String> mapData;
private Properties propertiesData;
public String[] getArrayData() {
return arrayData;
}
public void setArrayData(String[] arrayData) {
this.arrayData = arrayData;
}
public List<String> getListData() {
return listData;
}
public void setListData(List<String> listData) {
this.listData = listData;
}
public Set<String> getSetData() {
return setData;
}
public void setSetData(Set<String> setData) {
this.setData = setData;
}
public Map<String, String> getMapData() {
return mapData;
}
public void setMapData(Map<String, String> mapData) {
this.mapData = mapData;
}
public Properties getPropertiesData() {
return propertiesData;
}
public void setPropertiesData(Properties propertiesData) {
this.propertiesData = propertiesData;
}
@Override
public String toString() {
return "CollectionData [arrayData=" + Arrays.toString(arrayData)
+ ", listData=" + listData + ", setData=" + setData
+ ", mapData=" + mapData + ", propertiesData=" + propertiesData
+ "]";
}

给定的类

测试代码:

 public class Test01 {
@Test
public void fun01() {//测试初始化方法和销毁方法
String xmlPath = "cn/itcast/c_bean_xml/e_arry_collection_Map/applicationContext.xml";//给定xml文件路径
ApplicationContext applicationContext =new ClassPathXmlApplicationContext(xmlPath);//加载spring配置文件 CollectionData conllectionData=(CollectionData) applicationContext.getBean("collectionData");//填写id名称,使用IOC容器得到实例
System.out.println(conllectionData); } }

测试代码

二、基于注解进行bean的装配

1.注解的作用:主要是用来替代XML配置文件的,我们可以将在spring配置文件用注解的方式进行替换

 2.注解使用前提:添加命名空间,让spring扫描含有注解类

添加命名空间的格式在:spring-framework-3.2.0.RELEASE\docs\spring-framework-reference\html\xsd-config.html打开找到下图的地方将加粗的黑体加入spring配置文件

<context:component-scan base-package="cn.itcast.d_zhujie"></context:component-scan>在spring配置文件写入这个配置让spring去扫描这个包下所有类的注解

3.关于替代spring的注解分类

1. @Component取代<bean class="">

@Component("id") 取代 <bean id="" class="">

2.web开发,提供3个@Component注解衍生注解(功能一样)取代<bean class="">

@Repository :dao层

@Service:service层

@Controller:web层

3.依赖注入 :给私有字段在字段上面设置注解,也可以给setter方法上设置注解效果是一样的

普通值:@Value("")

引用值:

方式1:按照【类型】注入

@Autowired

方式2:按照【名称】注入1

@Autowired

@Qualifier("名称")

方式3:@Resource

4.生命周期

初始化:@PostConstruct

销毁:@PreDestroy

5.作用域

@Scope("prototype") 多例

4.模拟javaweb的三层架构来编写,将配置文件全部用注解代替

web层:

 @Controller("userAction")
@Scope("prototype")
public class UserAction {
@Autowired//按照类型注入
private UserService userService; public String execute(){
userService.addUser();
System.out.println("Action执行了");
return "success";
} }

web层的UserAction动作类

Service层:

 @Service("userService")//使用注解的前提是要在xml文件中添加命名空间,还要加入扫描配置
public class UserServiceImpl implements UserService { private UserDao userDao; public void addUser() {
userDao.save(); } public UserDao getUserDao() {
return userDao;
} // @Autowired单独写这个是第一种安装类型注入
// @Qualifier("userDao")//按名称注入这是第二种 @Resource//这个和按照类型有点类似这是第三种
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
} @PostConstruct//初始化方法
public void myInit(){
System.out.println("初始化方法执行了"); }
@PreDestroy//销毁方法
public void myDestory(){
System.out.println("销毁方法执行了");
}
}

service层

Dao层:

 @Repository("userDao")
public class UserDaoImpl implements UserDao { public void save() {
System.out.println("添加用户成功!!!"); } }

Dao层

测试代码:

 public class Test01 {
@Test
public void fun01() {//测试初始化方法和销毁方法
String xmlPath = "cn/itcast/d_zhujie/applicationContext.xml";
ClassPathXmlApplicationContext applicationContext =new ClassPathXmlApplicationContext(xmlPath);
//使用默认构造创建的实例
UserAction userAction=(UserAction) applicationContext.getBean("userAction");//填写id名称
UserAction userAction2=(UserAction) applicationContext.getBean("userAction");//填写id名称
//用来比对多例的配置有没有生效
System.out.println(userAction+"\n"+userAction2);
//执行方法并打印成功结果
System.out.println(userAction.execute());
//关闭IOC容器可以看到销毁方法执行
applicationContext.close(); }

测试注解完整代码

三、注解和xml混合使用时

1.将所有的bean都配置xml中

<bean id="" class="">

2.将所有的依赖都使用注解

@Autowired

默认不生效。为了生效,需要在xml配置:<context:annotation-config>

总结:

注解1:<context:component-scan base-package=" ">

注解2:<context:annotation-config>

1.一般情况两个注解不一起使用,因为写了第一个第二个写了也没用,因为它会使注入注解自动生效

2. “注解1”扫描含有注解(@Component 等)类,注入注解自动生效。

“注解2”只在xml和注解(注入)混合使用时,使注入注解生效。

day01_2spring3的更多相关文章

随机推荐

  1. java提取字符串数字,Java获取字符串中的数字

    ================================ ©Copyright 蕃薯耀 2020-01-17 https://www.cnblogs.com/fanshuyao/ 具体的方法如 ...

  2. [MongoDB]MongoDB的ObjectId组成

    一.ObjectId的组成首先通过终端命令行,向mongodb的collection中插入一条不带“_id”的记录.然后,通过查询刚插入的数据,发现自动生成了一个objectId“5e4fa350b6 ...

  3. 硬核干货 | C++后台开发学习路线

    2020秋招提前批 C/C++相关开发 拿到腾讯.华为等offer 学习路线及时间安排 推荐时间为4个月,包括四部分:语言,计算机基础知识,项目基础知识,项目实践. 语言 推荐学习1个月 学习方针:视 ...

  4. javaweb实现注册页面(数据库连接以及ajax验证)

    先放效果图 可实现js实时验证        可实现ajax实时验证注册信息是否存在   页面实现要求 1登录账号:要求由6到12位字母.数字.下划线组成,只有字母可以开头:(1分) 2登录密码:要求 ...

  5. pip淘宝镜像安装

    pip install virtualenvwrapper-win pip install -i https://pypi.tuna.tsinghua.edu.cn/simple virtualenv ...

  6. 微信小程序报错TypeError: this.setData is not a function

    今天在练习小程序的时候,遇到小程序报错 对于处于小白阶段的我,遇到这种报错,真还不知道是错从何来,只有一脸蒙逼,后来通过查询,终于知道了问题所在,下面对这一问题做一记录 小程序默认中是这么写的 onL ...

  7. windows10 找回windows照片查看器的方法

    突然发现windows10自带的图片查看器打开预览查看速度还是可以的,但是却找不到了,,,,, 下面就是如何找回 windows 图片查看器的操作了,只需要运行一个bat程序即可!!!!!! 随便新建 ...

  8. 题解 AT5632 【Sum of Two Integers】

    在幼儿园的时候,我们就学习过把一个数分成\(a\)与\(b\),我们只需要用计算机来模拟这个过程就可以了. 我们先从奇数开始看起,以\(5\)为例: 我们可以发现,\(5\)可以分成\(1\)和\(4 ...

  9. GaussDB T 单机模式手工建库

    目录 你需要知道的 创建文件夹 编辑参数文件 将数据库启动到 NOMOUNT 状态 连接实例查询状态 创建数据库PROD1 如何连接原来 GAUSS 数据库 相关文章 GaussDB T 单机搭建 G ...

  10. substring && substr

    let string = '0123456';string.substring(0,3);//start: number, end?: number 012(而非 0123)string.substr ...