目录
1.2:spring框架的好处(结合Spring体系结构分析)
5.4:SpEl注入(Spring表达式语言注入 #{ 属性})
7.1:bean管理注解 默认使用构造函数实例化(对应上边的Bean实例化方式)
7.2:自动装配注解(对应上边的Springbean的属性注入,不需要set方法)
1:什么是Spring
1.1:Spring概述
Spring是java的一个轻量级的开源框架,它最初是由 Rod Johnson 编写的,并且于 2003 年 6 月首次在 Apache 2.0 许可下发布。为了创建性能良好,易于维护,便于测试的java代码。
1.2:spring框架的好处(结合Spring体系结构分析)
要想了解spring的框架的好处,我们需要知道Spring框架的体系结构,spring有很多个模块组成,了扩展性和兼容性很强,不同的spring模块都有各自的优点,我们要想知道Spring的优点,就要熟知Spring的体系结构
Spring的体系结构如下:
2:Spring的IOC
Spring的Ioc功能:主要是控制反转、依赖注入
控制反转:是由Spring的核心容器提供的。Ioc的功能主要摆脱类和类之间的强烈依赖性,有我们以前的代码控制类之间互相new创建对象,改成由容器创建对象。
依赖注入:在我们需要某一个类的时候,不用通过new创建,而是根据需求通过配置文件注入需要的类
springIoc之前:
springIoc之后:
2.1:未使用Spring的Ioc之前
代码示例:此处代码耦合性强,不利于维护,牵一发而动全身
// 传统方法直接new出来实现类,耦合性强
@Test
public void test() {
User u = new User(2, "张三", "123456");
// 1:通过new创建对象,现象接口编程中,类中添加属性方法在实现类中的时候
// 需要通过new实现类,然后set赋值属性字段
UserServiceImpl userService = new UserServiceImpl();
userService.setFile("属性字段");
// 2: 通过new创建对象,面向接口编程功改变的时候,需要修改代码切换实现类
// UserService userService1=new UserServiceImpl();
userService.add(u);
}
2.2:使用Spring的Ioc之后
通过配置文件有beanFactory来读取配置文件,然后管理所有的ben
代码示例:
// Spring 注入的方式来实现
@Test
public void test1() {
// 创建bean工厂
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
// 2:通过工厂获取类
UserService userService = (UserService) applicationContext.getBean("userService");
//3.调用类方法
userService.selectById(0);
((AbstractApplicationContext) applicationContext).close();
}
配置文件示例:
<!--默认构造方式 bean的初始方法init-method bean的销毁方法destroy-method -->
<bean id="userService" class="com.thit.service.impl.UserServiceImpl" >
<property name="file" value="注入字段"></property>
</bean>
3:SpringBean的实例化方式(控制反转三种方式 主流的构造函数实例化bean)
前边的简单例子我们可以看到可以通过spring配置文件来实例化bean。接下来主要介绍三种bean的实例方式
3.1:构造函数实例化bean(主流bean实例化方法)
代码示例:
public class Bean1 {
public Bean1() {
System.out.println("构造方法创建bean");
}
}
配置文件:
<!--默认无参构造方式 bean的初始方法init-method bean的销毁方法destroy-method -->
<bean id="b1" class="com.thit.controller.Bean1">
</bean>
<!--有参构造方式,无参构造方法删除 -->
<!--
lazy-init="true" 懒加载 spring容器加载的时候没有实例化bean 只有获取bean的时候才创建
scope="singleton" 单例 放到单例池中
cope="prototype" 多例 使用的时候创建 因为不知道要创建几个,所有使用的时候创建
init-method="init1" 参数是方法名字 构造函数执行完毕 执行初始化方法
destroy-method="destory1" 参数是方法名字 构造函数执行完毕 执行销毁化方法(只有单例有效 一个实例可以销毁 多例无效 jvm负责)
constructor-arg name="id" value="2" 有参构造函数创建bean
-->
<bean id="user" name="aaa,bbb,ccc" class="com.thit.pojo.User"
scope="singleton"
lazy-init="false"
init-method="init1"
destroy-method="destory1">
<constructor-arg name="id" value="2"></constructor-arg>
<constructor-arg name="name" value="李四"></constructor-arg>
</bean>
3.2:静态工厂
代码示例:
public class Bean2 {
}
public class Bean2Factory {
//此处为静态方法
public static Bean2 creatBean2() {
System.err.println("静态工厂构建bean2");
//此处创建bean2
return new Bean2();
}
}
配置文件:
<!--静态工厂,配置工厂bean,工厂含有生成bean的静态方法, 指定工厂生成bean2的方法 -->
<bean id="b2" class="com.thit.controller.Bean2Factory" factory-method="creatBean2">
</bean>
3.3:实例化工厂
代码示例:
public class Bean3 {
}
public class Bean3Factory {
//实例工厂:此处非静态方法
public Bean3 creatBean3() {
System.out.println("实例工厂构建bean3");
//此处创建bean3
return new Bean3();
}
}
配置文件:
<!--实例工厂,配置工厂bean -->
<bean id="b3Factory" class="com.thit.controller.Bean3Factory" >
</bean>
<!-- 指定bean3工厂是b3Factory,然后指定工厂方法 -->
<bean id="b3" factory-bean="b3Factory" factory-method="creatBean3">
</bean>
以上介绍了bean的三种实例换方法,实例化化的bean归Spring的beanFactory来管理这些bean,那么bean的生命周期是怎么样的呢?
4:Bean的生命周期
bean的生命周期细分的话,分为11步,但是其中比较主要的步骤是
第一步:执行构造方法 spring对bean进行实例化,默认bean是单例
第二步: 指定bean的set方法,spring对bean进行依赖注入
第三步: 如果bean实现了BeanNameAware接口,spring将bean的id传给setBeanName()方法
第4.0步: 如果bean实现了BeanFactoryAware接口,执行setBeanFactory(BeanFactory beanFactory)
第四步:如果bean实现了ApplicationContextAware()接口,spring将调用setApplicationContext()方法将应用上下文的引用传入
第五步 :如果bean实现了BeanPostProcessor接口(后置处理器,负责处理所有的bean,会执行多次)spring将调用它们的postProcessBeforeInitialization接口方法(重点)
第六步:如果bean实现了InitializingBean接口,spring将调用afterPropertiesSet方法,
第七步 :执行配置spring配置文件中的的bean(init-method="initTest" )的初始化方法(初始化方法重点)
第八步: 如果bean实现了BeanPostProcessor接口后置处理器,负责处理所有的bean,spring将调用它们的postProcessAfterInitialization接口方法(重点方法,可以拦截指定bean的指定方法)
------------------------------------------
第九步 :执行bean自己的方法
-----------------------------------------
第十步:如果bean实现了DisposableBean 接口,执行配置的bean(destroy-method="destryTest")的销毁方法(单例有效)(重点)
4.1:代码实例
代码如下:
// 接口
public interface Bean1Intreface {
public void run() ;
public void Save();
public void run1() ;
}
//实现类
//BeanPostProcessor是bean的后置处理器
public class Bean1 implements Bean1Intreface, BeanNameAware, ApplicationContextAware, InitializingBean, DisposableBean {
String name;
public Bean1() {
System.out.println("第一步:构造方法创建bean");
}
public void run() {
System.out.println("第九步:执行类的自己的run方法:"+name);
}
public void initTest() {
System.out.println("第七部:执行配置的bean(init-method=\"initTest\" )的初始化方法-----------");
}
//单例模式才会调用销毁方法,因为多利调用不可控
public void destryTest() {
System.out.println("第十一步:执行配置的bean(destroy-method=\"destryTest\")的销毁方法(单例有效)");
}
public String getName() {
return name;
}
public void setName(String name) {
System.out.println("第二步:执行bean的set方法---");
this.name = name;
}
@Override
public void destroy() throws Exception {
// TODO Auto-generated method stub
System.out.println("第十步:执行spring的销毁方法(单例情况下有效)");
}
@Override
public void afterPropertiesSet() throws Exception {
// TODO Auto-generated method stub
System.out.println("第六步:属性设置后执行");
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
// TODO Auto-generated method stub
System.out.println("第四步:获取工厂信息");
}
@Override
public void setBeanName(String name) {
// TODO Auto-generated method stub
System.out.println("第三步:获取bean的名字——"+name);
}
public void Save() {
// TODO Auto-generated method stub
System.out.println("第九步:执行增强save方法--------");
}
@Override
public void run1() {
// TODO Auto-generated method stub
}
}
//bean的后置拦截器BeanPostProcessor
//bean的后置处理器
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
// TODO Auto-generated method stub
System.out.println("第五步:bean后置处理器初始化bean之前1:"+bean+"\t"+beanName);
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
// TODO Auto-generated method stub
System.out.println("第八步:bean后置处理器初始化bean之后:"+bean+"\t"+beanName);
//bean的名字是b1
if (beanName.equals("b1")) {
System.out.println("增强指定Bean1类");
Object proxy=Proxy.newProxyInstance(
bean.getClass().getClassLoader(),
bean.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// TODO Auto-generated method stub
//增强指定的方法
if("Save".equals(method.getName())) {
System.out.println("-----增强指定的Save方法-----");
return method.invoke(bean,args);
}
return method.invoke(bean,args);
}
});
return proxy;
}else {
return bean;
}
}
}
配置文件如下:
<!--默认构造方式 bean的初始方法init-method bean的销毁方法destroy-method -->
<bean id="b1" class="com.thit.controller.Bean1"
scope="singleton" init-method="initTest" destroy-method="destryTest">
<property name="name" value="天天"></property>
</bean>
<!-- 自动加载 -->
<bean class="com.thit.controller.MyBeanPostProcessor"></bean>
结果分析:
5:Springbean的属性注入 (依赖注入方式3种 主流的是set注入和构造函数注入 )
5.1:set注入(主流)
代码如下:
public class Student2 {
private int id;
private String naem;
private Student student;
set--get--方法
@Override
public String toString() {
return "Student2 [id=" + id + ", naem=" + naem + ", student=" + student + "]";
}
}
配置文件如下:
<!--构造方法注入属性-->
<bean id="stu1" class="com.thit.ioc.Student">
<constructor-arg name="id" value="123"></constructor-arg>
<constructor-arg name="naem" value="张三"></constructor-arg>
</bean>
<!--set方法注入属性-->
<bean id="stu2" class="com.thit.ioc.Student2">
<property name="id" value="111"></property>
<property name="naem" value="set注入"></property>
<property name="student" ref="stu1"></property>
</bean>
5.2:构造函数注入(主流)
代码如下:
public class Student {
private int id;
private String naem;
public Student() {
super();
}
public Student(int id, String naem) {
super();
this.id = id;
this.naem = naem;
}
}
配置文件如下:
<!--构造方法注入属性-->
<bean id="stu1" class="com.thit.ioc.Student">
<constructor-arg name="id" value="123"></constructor-arg>
<constructor-arg name="naem" value="张三"></constructor-arg>
</bean>
5.3:命名空间注入(p:类属性字段)
代码如上只需要添加set方法:p
配置文件如下:
<!--命名空间依赖set方法 p:属性 直接引用-->
<bean id="stu1" class="com.thit.ioc.Student" p:id="11" p:naem="P命名空间赋值22">
</bean>
<!--命名空间依赖set标签 set方法注入属性-->
<bean id="stu2" class="com.thit.ioc.Student2"
p:id="22" p:naem="命名空间赋值22" p:student-ref="stu1">
</bean>
5.4:SpEl注入(Spring表达式语言注入 #{ 属性})
代码如上无需更改
配置文件如下:
<!--Spel注入 语法是 #{}-->
<bean id="stu1" class="com.thit.ioc.Student" >
<property name="id" value="#{'1'}"></property>
<property name="naem" value="#{'Spel注入111'}"></property>
</bean>
<!--Spel注入 语法是 #{beanid}-->
<bean id="stu2" class="com.thit.ioc.Student2">
<property name="id" value="#{'2'}"></property>
<property name="naem" value="#{'Spel注入222'}"></property>
<property name="student" value="#{stu1}"></property>
</bean>
6:复杂类型注入
代码如下:
private String[] arrs;//数组注入
private List<String> list;//list注入
private Set<String> set;//set注入
private Map<Integer,String> map;//map注入
private Properties ps;//Properties注入
省略set get方法
配置文件如下:
<bean name="stu3" class="com.thit.ioc.Student3" >
<!-- 数组注入 -->
<property name="arrs">
<list>
<value>arrs1</value>
<value>arrs2</value>
<value>arrs3</value>
<value>arrs2</value>
</list>
</property>
<!-- list注入 -->
<property name="list">
<list>
<value>list1</value>
<value>list2</value>
<value>list3</value>
<value>list4</value>
</list>
</property>
<!-- set注入 有去重功能 -->
<property name="set">
<set>
<value>set1</value>
<value>set2</value>
<value>set3</value>
<value>set1</value>
</set>
</property>
<!-- map注入 有去重功能 -->
<property name="map">
<map>
<entry key="1" value="map1"></entry>
<entry key="2" value="map2"></entry>
<entry key="1" value="map3"></entry>
</map>
</property>
<!-- propre注入 有去重功能 -->
<property name="ps">
<props>
<prop key="p1">aaa</prop>
<prop key="p2">bbb</prop>
<prop key="p3">ccc</prop>
<prop key="p1">ddd</prop>
</props>
</property>
</bean>
7:bean的注解
前面使用了xml的配置文集管理和注入bean,但是配置文件写起来比较麻烦,可以通过注解来使用。
第一步:导入aop包
第二步:打开注解扫描
<!-- 开启注解扫描 扫描包-->
<context:component-scan base-package="com.thit.*"></context:component-scan>
7.1:bean管理注解默认使用构造函数实例化(对应上边的Bean实例化方式)
@Component("bean名字"),能实现对所有的类进行注解,但是Component不利于三层架构,所以一个注解扩展成了三个来对应不同的业务逻辑层。
@Configuration(定义类 相当于配置文件的beans标签,用来替换配置文件,不需要配置文件了)
@Bean(定义方法,返回bean)
------------------------------------------------------------------
@Controller() //对controller标注
@Service() //对service标注
@Repository() //对dao标注
---------------------------------------
@Scope("prototype") //单例
@PostConstruct //注解初始化方法,替代配置
@PreDestroy //注解销毁方法,替代配置
@Controller("uControl")
@Scope("prototype")
public class UserController {
//不需要set方法
@Value("controller传输的名字")
String name;
//默认按照类型,自动将service注入,当有两个实现类的时候会有问题
//此时通过Qualifier 设置名字注入
// @Autowired
// @Qualifier("uService2")
//resource注解相当于@Autowired和Qualifier的结合
@Resource(name="uService1")
UserService uService;
//注解初始化方法,替代配置
@PostConstruct
public void initT(){
System.out.println("Controller的bean的初始化方法");
}
//注解销毁方法,替代配置
@PreDestroy
public void destoryT(){
System.out.println("Controller的bean的销毁方法,单例下有用");
}
public void test() {
System.out.println("第一步:执行controller的方法");
uService.add();
System.out.println("----------------------");
uService.run(name);
}
其他注解
7.2:自动装配注解(对应上边的Springbean的属性注入,不需要set方法)
===================================================================
普通属性注入:@value
//不需要set方法
@Value("controller传输的名字")
String name;
====================================================================
类注入:@Autowired+@Autowired = @Resource(name="uService1")
方法一:@Autowired(byType) +@Autowired
//默认按照类型,自动将service注入,当有两个实现类的时候会有问题
//此时通过Qualifier 设置名字注入
// @Autowired
// @Qualifier("uService2")
方法二:@Resource(name="")
//resource注解相当于@Autowired和Qualifier的结合(byType 和byName)
@Resource(name="uService1")
UserService uService;
====================================================================
7.3:xml和注解混合使用
我们使用xml来配置bean,使用@Resource属性注入。xml和注解分工合作。
需要增加一行配置
<!-- 开启注解扫描 扫描包-->
<context:component-scan base-package="com.thit.*"></context:component-scan>
<!-- 单独使用属性注入注解 controller service dao注解用不了 关闭注解扫描-->
<context:annotation-config></context:annotation-config>
package com.thit.daoImpl;
import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.*;
import javax.sql.DataSource;
@Configuration
//扫描包 容器会把包和子包下边的注解都扫描到
// 相当于<context:component-scan base-package="com.thit"/>
@ComponentScan("com.thit")
//<!--作用:引入外部文件 在spring中可以直接使用-->
//<context:property-placeholder location="classpath*:db.properties"/>
@PropertySource(value = {"classpath:db.properties"})
//相当于 <import resource="datasource.xml"/>
@Import(OtherBean.class)
public class SpringConfig {
@Value("${password1}")
String password;
@Bean
public DataSource dataSource1(){
DruidDataSource dataSource=new DruidDataSource();
System.out.println("密码:"+password);
return dataSource;
}
}
public class OtherBean {
String name;
// @Autowired
// StudentDao studentDao;
/**
* 方法的参数注入
* @value 普通属性
*
* @Autowired 自动注入
* @Qualifier("studentDaoImpl") 指定这个注解也可以注入
*
* @return
*/
@Bean
public DataSource dataSource2(@Value("${password1}") String username, @Qualifier("studentDaoImpl")
StudentDao studentDao){
DruidDataSource dataSource=new DruidDataSource();
System.out.println("username:"+username);
//studentDao.add();
System.out.println("studentDao:"+studentDao);
return dataSource;
}
}