day01_2spring3
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的更多相关文章
随机推荐
- java提取字符串数字,Java获取字符串中的数字
================================ ©Copyright 蕃薯耀 2020-01-17 https://www.cnblogs.com/fanshuyao/ 具体的方法如 ...
- [MongoDB]MongoDB的ObjectId组成
一.ObjectId的组成首先通过终端命令行,向mongodb的collection中插入一条不带“_id”的记录.然后,通过查询刚插入的数据,发现自动生成了一个objectId“5e4fa350b6 ...
- 硬核干货 | C++后台开发学习路线
2020秋招提前批 C/C++相关开发 拿到腾讯.华为等offer 学习路线及时间安排 推荐时间为4个月,包括四部分:语言,计算机基础知识,项目基础知识,项目实践. 语言 推荐学习1个月 学习方针:视 ...
- javaweb实现注册页面(数据库连接以及ajax验证)
先放效果图 可实现js实时验证 可实现ajax实时验证注册信息是否存在 页面实现要求 1登录账号:要求由6到12位字母.数字.下划线组成,只有字母可以开头:(1分) 2登录密码:要求 ...
- pip淘宝镜像安装
pip install virtualenvwrapper-win pip install -i https://pypi.tuna.tsinghua.edu.cn/simple virtualenv ...
- 微信小程序报错TypeError: this.setData is not a function
今天在练习小程序的时候,遇到小程序报错 对于处于小白阶段的我,遇到这种报错,真还不知道是错从何来,只有一脸蒙逼,后来通过查询,终于知道了问题所在,下面对这一问题做一记录 小程序默认中是这么写的 onL ...
- windows10 找回windows照片查看器的方法
突然发现windows10自带的图片查看器打开预览查看速度还是可以的,但是却找不到了,,,,, 下面就是如何找回 windows 图片查看器的操作了,只需要运行一个bat程序即可!!!!!! 随便新建 ...
- 题解 AT5632 【Sum of Two Integers】
在幼儿园的时候,我们就学习过把一个数分成\(a\)与\(b\),我们只需要用计算机来模拟这个过程就可以了. 我们先从奇数开始看起,以\(5\)为例: 我们可以发现,\(5\)可以分成\(1\)和\(4 ...
- GaussDB T 单机模式手工建库
目录 你需要知道的 创建文件夹 编辑参数文件 将数据库启动到 NOMOUNT 状态 连接实例查询状态 创建数据库PROD1 如何连接原来 GAUSS 数据库 相关文章 GaussDB T 单机搭建 G ...
- substring && substr
let string = '0123456';string.substring(0,3);//start: number, end?: number 012(而非 0123)string.substr ...