Spring核心
- IOC容器:控制反转,把创建对象过程交给Spring进行管理
- Aop:面向切面编程,不修改原代码的情况下进行功能的拓展
Spring特点
- 便于解耦
- 框架整合
- 事务操作
如何使用Spring创建对象
<!--1.导入jar包-->
<bean id = "id1" class = "package.dir.class"></bean>
//2.在service类中加载Spring配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("springconfig.xml");
//3.获取配置创建的对象
MyClass clazz = context.getBean("id", MyClass.class);
IOC容器(重点)
- 控制反转,把创建对象、对象之间的调用,交给Spring进行管理
- 目的:降低耦合度
IOC底层原理
过程:xml文件-->xml解析-->工厂模式-->反射
IOC接口(BeanFactory)
- IOC思想是基于IOC容器完成的,IOC容器的底层是对象工程
- Spring提供IOC容器实现方式:(两个接口)
- BeanFactory:IOC容器基本实现,是Spring内部的使用接口,不提供给开发人员使用
- 加载配置文件时候不会创建对象,在获取对象时才去创建创建对象。
- ApplicationContext:BeanFactory的子接口,提供强大的功能,开发人员使用
- 加载配置文件的时候会把配置文件对象进行创建
- ApplicationContext接口又有几个实现类,常用的有如下两个:
- ClassPathXmlApplicationContext("配置文件名.xml")
- FileSystemXmlApplicationContext("盘符路径/配置文件名.xml")
- BeanFactory:IOC容器基本实现,是Spring内部的使用接口,不提供给开发人员使用
IOC操作Bean管理
- 什么是Bean管理
- Spring创建对象
- Spring注入属性
IOC操作Bean管理(基于xml)
- 创建对象
<bean id="user" class="com.ken.spring.User"></bean>
在Spring配置文件中,使用bean标签,标签里面添加对应属性,就可以实现对象创建
在bean标签有很多属性
id属性:唯一标识
class属性:类全路径(包类路径)
创建对象时,默认执行无参数构造方法
- 注入属性(DI) :依赖注入
使用set方法进行注入(无参数构造器)
public class Book { private String bname; private String bauthor; //创建属性对应的set方法 public void setBname(String bname) { this.bname = bname; } public void setBauthor(String bauthor) { this.bauthor = bauthor; } public void testDemo(){ System.out.prinln(bname + ":" + bauthor); } }
<bean id="book" class="com.ken.spring.Book"> <!--在bean标签内添加property标签--> <property name="bname" value="葵花宝典"></property> <property name="bauthor" value="达摩老祖"></property> </bean>
public void test(){ ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml"); Book book = context.getBean("book", Book.class); System.out.println(book); book.testDemo(); }
使用set方法进行注入(有参数构造器)
public class Order { private String orderName; private String address; public Order(String orderName, String address) { this.orderName = orderName; this.address = address; } public void orderTest(){ System.out.println(orderName + ":" + address); } }
<bean id="order" class="com.ken.spring.Order"> <constructor-arg name="orderName" value="JD"></constructor-arg> <constructor-arg name="address" value="Home"></constructor-arg> </bean>
public void test(){ ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml"); Order order = context.getBean("order", Order.class); System.out.println(order); order.orderTest(); }
****xml注入其他类型的属性
- 字面量
- null值
<property name="xxxx"> <null/> </property>
包含特殊符号的属性值
<property name="xxx" value="<Ken>"></property> <!--方式一:""中的<>会参与编译,故使用转义字符:<内容>--> <property name="xxx"><value><![CDATA[Ken]]</value></property> //方式二:使用![CDATA[内容]]
注入外部bean属性
创建service类和dao类
在service类调用dao类中的方法
在Spring配置文件中进行配置
public class UserService { private UserDAO userDAO; public void setUserDAO(UserDAO userDAO) { this.userDAO = userDAO; } public void add(){ System.out.println("Service add方法"); userDAO.update(); } } public class UserDaoImpl implements UserDAO{ @Override public void update() { System.out.println("UserDAO update"); } } public interface UserDAO { public void update(); }
<bean id="userService" class="com..spring.Service.UserService"> <!--注入userDAO对象--> <property name="userDAO" ref="userDaoImpl"></property> </bean> <bean id="userDaoImpl" class="com.ken.spring.DAO.UserDaoImpl"> </bean>
注入内部bean属性
一对多关系:例部门和员工
一个部门有多个员工,一个员工属于一个不行
部门是一,员工是多
在实体类之间表示一对多的关系
public class Dept { private String dname; public void setDname(String dname) { this.dname = dname; } @Override public String toString() { return "Dept{" + "dname='" + dname + '\'' + '}'; } }
public class Emp { private String ename; private String gender; //员工属于某一个部门,使用对象形式表示 private Dept dept; public void setDept(Dept dept) { this.dept = dept; } public void setGender(String gender) { this.gender = gender; } public void setEname(String ename) { this.ename = ename; } public void add(){ System.out.println(ename + "::" + gender + "::" + dept); } }
在Spring配置文件中进行配置
<!-- 内部bean--> <bean id="emp" class="com.ken.spring.Bean.Emp"> <property name="ename" value="Ce"></property> <property name="gender" value="woman"></property> <property name="dept"> <bean id="dept" class="com.ken.spring.Bean.Dept"> <property name="dname" value="JavaDevelop"></property> </bean> </property> </bean>
注入属性-----级联赋值
<!--内部bean--> <bean id="emp" class="com..spring.Bean.Emp"> <property name="ename" value="Ce"></property> <property name="gender" value="woman"></property> <!--******级联赋值*******--> <property name="dept" ref="dept"></property> </bean> <bean id="dept" class="com.ken.spring.Bean.Dept"> <property name="dname" value="TestDep"></property> </bean>
****xml注入集合属性
public class Stu { private String[] courses; private List<String> list; private Map<String,String> map; private Set<String> set; public void setCourses(String[] courses) { this.courses = courses; } public void setList(List<String> list) { this.list = list; } public void setMap(Map<String, String> map) { this.map = map; } public void setSet(Set<String> set) { this.set = set; } }
- 注入数组类型属性
<!--数据类型属性注入--> <property name="courses"> <array> <value>java</value> <value>Mysql</value> </array> </property>
注入List集合类型属性
<!--List类型属性注入--> <property name="list"> <list> <value>张三</value> <value>唐三</value> </list> </property>
注入Map集合类型属性
<!--Map类型属性注入--> <property name="map"> <map> <entry key="JAVA" value="java"/> <entry key="PHP" value="php"/> </map> </property>
注入Set集合类型属性
<!--Set类型属性注入--> <property name="set"> <set> <value>Mysql</value> <value>Redis</value> </set> </property>
结果为:
Stu{courses=[java, Mysql], list=[张三, 唐三], map={JAVA=java, PHP=php}, set=[Mysql, Redis]}
****List集合中,值是对象
<property name="courseList"> <list> <ref bean="course1"></ref> <ref bean="course2"></ref> </list> </property>
<bean id="course1" class="com.ken.spring.collectiontype.Course"> <property name="cname" value="Spring框架"></property> </bean> <bean id="course2" class="com.ken.spring.collectiontype.Course"> <property name="cname" value="Redis框架"></property> </bean>
**** 把集合注入部分提取
- 在Spring配置文件里引入空间名称util
<?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:p="http://www.springframework.org/schema/p" xmlns:util="http://www.springframework.org/schema/util" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-uitl.xsd">
使用util标签完成list集合注入提取
<!--注入List集--> <util:list id="bookList"> <value>Java核心卷(一)</value> <value>Java核心卷(二)</value> <value>Java编程思想</value> </util:list> <bean id="book" class="com..spring.collectiontype.Book"> <property name="list" ref="bookList"> </property> </bean> </beans>
- Spring有两种类型的bean,一种是普通bean,一种是工厂bean (FactoryBean)
- 普通bean:在配置文件中定义的bean类型就是返回类型
- 工厂bean:在配置文件中定义bean类型可以和返回类型不一致
- 第一步:创建类,让这个类作为工厂bean,实现接口FactoryBean
- 第二步:实现接口里的方法,在实现的方法中定义返回的类型
public class MyBean implements FactoryBean<Course> { //定义返回bean @Override public Course getObject() throws Exception { Course course = new Course(); course.setCname("abc"); return course; }
Course course = context.getBean("myBean", Course.class);
-
xml的自动装配:根据指定装配规则(属性名称或者属性类型),Spring自动将匹配到的属性进行注入
-
在bean标签中autowire配置自动装配
<bean id="" class="" autowire="byName"></bean> <bean id="" class="" autowire="byType"></bean>
-
byName根据属性名称注入,注入的id和类属性名称一样
-
byType根据属性类型注入
-
-
-
外部属性处理(IOC操作bean管理)
-
直接配置数据库信息
-
配置德鲁伊连接池(druid)
-
引入德鲁伊连接池的jar包
-
配置德鲁伊bean.xml
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassLoader" value="com.mysql.jdbc.Driver"></property> <property name="url" value="jdbc:mysql://localhost:3306/userDb"></property> <property name="username" value="root"></property> <property name="password" value="root"></property>
-
-
引入外部属性文件配置数据库连接池
-
创建外部属性文件(.properties),写入数据库信息
prop.driverClass=com.mysql.jdbc.Driver prop.url=jdbc:mysql://localhost:3306/userDb prop.userName=root prop.password=123456
-
把外部properties文件引入Spring配置文件
-
引入context 名称空间(在xml文件头配置)
xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
-
在Spring配置文件使用标签引入外部属性文件
<context:property-placeholder location="classpath:jdbc.properties"/> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassLoader" value="${prop.driverClass}"/> <property name="url" value="${prop.url}"/> <property name="username" value="${prop.userName}"/> <property name="password" value="${prop.password}"/>
-
-
-
IOC操作bean管理(基于注解)
- 注解格式:@注解名称(属性名称=属性值,属性名称=属性值,...)
- 作用:简化xml配置
○Spring针对Bean管理创建对象提供注解(重):
- @Component
- @Service (service层)
- @Controller(Web层)
- @Repository(dao层)
- 基于注解方式实现对象创建
- 引入依赖--->spring-aop-5.3.9.jar
- 开启组件扫描
<context:component-scan base-package= "com.atguigu.spring.dao,com.ken.spring.service"> </context:component-scan> <!--扫描多个包用","隔开--> <context:component-scan base-package="com.ken"> </context:component-scan> <!--扫描包的上层目录-->
在使用类之前添上注解
//注解中value属性值可以忽略不写 //默认值是类名称,首字母小写 @Component(value = "myClass") public class Myclass{ ... }
创建实例对象
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml"); MyClass myClass = context.getBean("myClass", Myclass.class);
- 组件扫描细节配置
- 扫描注解为Controller的类
<context:component-scan base-package="com.ken" use-default-filters="false"> <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </context:component-scan>
user-default-filters="false" 表示不使用默认filter,自己配置filter
context:include-filter 设置扫描包含内容
type="annotation" 表示根据注解类型进行扫描
expression="org.springframework.stereotype.Controller" 表示扫描Controller注解
扫描注解不为Controller的类
<context:component-scan base-package="com.ken"> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </context:component-scan>
context:exclude-filter 设置排除内容
○基于注解方式实现属性注入
- @Autowired:根据属性类型自动装配
- @Qualifier:根据属性名称进行注入
- @Resource:类型、名称皆可
- @Value:注入普通类型
@AutoWired
- 把service和dao对象创建,在service和dao类添加创建对象注解
- 在service层注入dao对象,在service类添加dao类型属性,在属性上方添加注解
public interface UserDao { public void add(); }
@Repository public class UserDaoImpl implements UserDao{ private UserDao userDao; @Override public void add() { System.out.println("dao add..."); } }
//注解中value属性值可以忽略不写 //默认值是类名称,首字母小写 @Service(value = "userService") public class UserService { //定义dao类型属性 //无需添加set方法 //添加注入属性注解d @Autowired //根据类型进行注入 private UserDao userDao; public void add(){ System.out.println("service add...."); userDao.add(); } }
@Qualifier
与AutoWired不同的是
- 要设置Repository中的value值
@Repository(value = "userDaoImpl1")
在@Autowired下添加@Qualifier注解
@Autowired @Qualifier(value = "userDaoImpl1")
@Resource(根据名称进行注入)
@Resource(name = "userDaoImpl1")
@Value(注入普通类型属性)
@Value(value = "")
完全注解开发
创建配置类,替代".xml"文件
@Configuration @ComponentScan(basePackages = {"包路径"}) public void ken(){ }
Bean的作用域和生命周期
bean的作用域
- 在Spring中,设置创建bean实例是单实例还是多实例
- 在Spring中,默认情况下,创建的bean是单实例对象
- 如何设置单实例or多实例
- Spring配置文件bean标签中scope用于设置单实例(Singleton)还是多实例(Prototype)
<bean id="" class="" scope=""></bean> <!--默认不写就是单实例singleton--> <bean id="" class="" scope="prototype"></bean>
singleton和prototype区别
单实例模式时,加载Spring配置文件时就会创建单实例对象
多实例模式时,在调用getBean方法()时才会创建多实例对象
bean的生命周期
(5步)bean的生命周期:
- 通过构造器创建bean实例(无参数构造器)
- 为bean的属性设置值和对外部bean的引用(调用set)
- 调用bean的初始化(init)的方法(手动配置)
<bean id="" class="" init-method=""></bean>
使用bean对象(获取到对象)
当容器关闭的时候,调用bean的销毁(destroy)的方法,需要进行配置销毁的方法
<bean id="" class="" init-method="" destroy-method=""></bean>
(7步)bean的生命周期:
- 通过构造器创建bean实例(无参数构造器)
- 为bean的属性设置值和对外部bean的引用(调用set)
- 把bean实例传递bean后置处理器的方法(postProcessBeforeInitialization)
- 调用bean的初始化(init)的方法(手动配置)
把bean实例传递bean后置处理器的方法(postProcessAfterInitialization)
bean可以使用了(对象获取到了)
- 当容器关闭时,调用bean的销毁(destroy)的方法(需要进行配置销毁的方法)
※添加后置处理器
- 创建类,实现接口BeanPostProcessor,创建后置处理器
public class MyBeanPost implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { System.out.println("在初始化之前的方法"); return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { System.out.println("在初始化之后的方法"); return bean; } }
- 在xml文件中,添加后置处理器
<!--配置后置处理器--> <bean id="myBeanPost" class=""> </bean>