Spring是一个开源框架
Spring为简化企业级开发而生,使用Spring,JavaBean就可以实现很多以前要靠EJB才能实现的功能。同样的功能,在EJB中要通过繁琐的配置和复杂的代码才能够实现,而在Spring中却非常的优雅和简洁。
Spring是一个IOC(DI)和AOP容器框架。
Spring的优良特性
① 非侵入式:基于Spring开发的应用中的对象可以不依赖于Spring的API
② 依赖注入:DI——Dependency Injection,反转控制(IOC)最经典的实现。
③ 面向切面编程:Aspect Oriented Programming——AOP
④ 容器:Spring是一个容器,因为它包含并且管理应用对象的生命周期
⑤ 组件化:Spring实现了使用简单的组件配置组合成一个复杂的应用。在 Spring 中可以使用XML和Java注解组合这些对象。
一站式:在IOC和AOP的基础上可以整合各种企业应用的开源框架和优秀的第三方类库(实际上Spring 自身也提供了表述层的SpringMVC和持久层的Spring JDBC)。
IOC描述的只是一种思想,而DI是IOC思想的具体表现。
<bean id="car" class="spring.di.Car">
<property name="brand" value="法拉利">property>
<property name="crop" value="Italy">property>
<property name="price" value="6000000">property>
bean>
//获取容器对象
ApplicationContext context = new ClassPathXmlApplicationContext("spring-di.xml");
Car car = context.getBean("car", Car.class);
System.out.println(car);
1、Spring自动匹配合适的构造器
<bean id="car1" class="spring.di.Car">
<constructor-arg value="奥迪" >constructor-arg>
<constructor-arg value="一汽" >constructor-arg>
<constructor-arg value="400000">constructor-arg>
bean>
public Car(String brand, String crop, Double price) {
this.brand = brand;
this.crop = crop;
this.price = price;
}
2、通过构造器索引赋值
<bean id="car1" class="spring.di.Car">
<constructor-arg value="奥迪" index="0" name="brand">constructor-arg>
<constructor-arg value="一汽" index="1">constructor-arg>
<constructor-arg value="400000" index="2">constructor-arg>
bean>
注:
1.通过类型区分重载的构造器:当同时有多构造器的时候在参数种类相同的时候优先匹配最后定义的构造器,这样就会产生一个问题,会让我们匹配到不想匹配的构造器,此时应该多声明一个type
<bean id="car1" class="spring.di.Car">
<constructor-arg value="奥迪" index="0" name="brand" type="java.lang.String">constructor-arg>
<constructor-arg value="一汽" index="1" type="java.lang.String">constructor-arg>
<constructor-arg value="400000" index="2" type="java.lang.Double">constructor-arg>
bean>
<bean id="car3" class="spring.di.Car"
p:brand="奔驰" p:crop="梅赛德斯" p:price="100000">
bean>
<bean id="book" class="spring.di.Book">
<property name="bookId" value="1001">property>
<property name="bookName">
<value>value>
property>
bean>
package spring.di;
public class Book {
private Integer bookId;
private String bookName;
public Integer getBookId() {
return bookId;
}
public void setBookId(Integer bookId) {
this.bookId = bookId;
}
public String getBookName() {
return bookName;
}
public void setBookName(String bookName) {
this.bookName = bookName;
}
@Override
public String toString() {
return "Book{" +
"bookId=" + bookId +
", bookName='" + bookName + '\'' +
'}';
}
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("spring-di.xml");
Book book = context.getBean("book", Book.class);
System.out.println(book);
}
}
<bean id="person" class="spring.di.Person">
<property name="id" value="1001">property>
<property name="name" value="zz">property>
<property name="car" ref="car">property>
bean>
注意:只可以引用IOC内部的对象实例
当bean实例仅仅给一个特定的属性使用时,可以将其声明为内部bean。内部bean声明直接包含在
或
元素里,不需要设置任何id或name属性。
<bean id="person1" class="spring.di.Person">
<property name="id" value="521">property>
<property name="name" value="Tom">property>
<property name="car">
<bean class="spring.di.Car">
<property name="brand" value="兰博基尼">property>
<property name="crop" value="德国">property>
<property name="price" value="10000000">property>
bean>
property>
bean>
<bean id="person2" class="spring.di.Person">
<property name="id" value="1002">property>
<property name="name" value="John">property>
<property name="car"><null/>property>
bean>
<bean id="personList" class="spring.di.PersonList">
<property name="name" value="Mary">property>
<property name="cars">
<list>
<ref bean="car"/>
<ref bean="car1"/>
<ref bean="car3"/>
list>
property>
bean>
package spring.di;
import java.util.List;
public class PersonList {
private String name;
private List<Car> cars;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<Car> getCars() {
return cars;
}
public void setCars(List<Car> cars) {
this.cars = cars;
}
@Override
public String toString() {
return "PersonList{" +
"name='" + name + '\'' +
", cars=" + cars +
'}';
}
@Test
public void testList(){
ApplicationContext context = new ClassPathXmlApplicationContext("spring-di.xml");
PersonList personList = context.getBean("personList", PersonList.class);
System.out.println(personList);
}
}
注意:
1、List也可以使用Array,因为IOC内部也封装了标签,因为Array底层也是List。
2、如果ref引用的值在之前的ref过程中被修改过值,那么这里再使用ref引用的话就是被修改之后的值。
<bean id="personMap" class="spring.di.PersonMap">
<property name="name" value="Jerry">property>
<property name="map">
<map>
<entry key="zz" value-ref="car">entry>
<entry key="pp" value-ref="car1">entry>
<entry key="ww" value-ref="car3">entry>
map>
property>
bean>
package spring.di;
import java.util.Map;
public class PersonMap {
private String name;
private Map<String, Car> map;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Map<String, Car> getMap() {
return map;
}
public void setMap(Map<String, Car> map) {
this.map = map;
}
@Override
public String toString() {
return "PersonMap{" +
"name='" + name + '\'' +
", map=" + map +
'}';
}
@Test
public void testMap(){
ApplicationContext context = new ClassPathXmlApplicationContext("spring-di.xml");
PersonMap personMap = context.getBean("personMap", PersonMap.class);
System.out.println(personMap);
}
}
<util:list id="listBean">
<ref bean="car"/>
<ref bean="car1"/>
<ref bean="car3"/>
util:list>
上面我们已经给bean打包好了listBean,所以我们可以在外面使用list的时候去调用listBean
bean id="personList" class="spring.di.PersonList">
<property name="name" value="Mary">property>
<property name="cars" ref="listBean">
property>
bean>
Spring中有两种类型的bean,一种是普通bean,另一种是工厂bean,即FactoryBean。
工厂bean跟普通bean不同,其返回的对象不是指定类的一个实例,其返回的是该工 厂bean的getObject方法所返回的对象。
工厂bean必须实现org.springframework.beans.factory.FactoryBean接口。
package spring.factoryBean;
import org.springframework.beans.factory.FactoryBean;
import spring.di.Car;
public class CarFactoryBean implements FactoryBean<Car> {
/**
* 工厂bean具体创建的bean对象是有getObject方法返回的
* @return
* @throws Exception
*/
@Override
public Car getObject() throws Exception {
return new Car("五菱", "五菱", 50000.0);
}
/**
* 返回具体的bean对象的类型
* @return
*/
@Override
public Class<?> getObjectType() {
return Car.class;
}
/**
* bean可以是单例的,也可以是原型的(非单例)
* @return
*/
@Override
public boolean isSingleton() {
return true;
}
}
配置文件如下:
<bean id="factoryBean" class="spring.factoryBean.CarFactoryBean">bean>
<bean id="address1" abstract="true">
<property name="city" value="beijing">property>
<property name="street" value="ChangAnJie">property>
bean>
<bean id="address2" class="spring.relation.Address" parent="address1">
<property name="street" value="WuDaoKou">property>
bean>
<bean id="address1" abstract="true">
<property name="city" value="beijing">property>
<property name="street" value="ChangAnJie">property>
bean>
<bean id="address3" class="spring.relation.Address" parent="address1" depends-on="address4">bean>
<bean id="address4" class="spring.relation.Address">bean>
<bean id="car" class="spring.scope.Car" scope="singleton">
<property name="brand" value="奥迪">property>
<property name="price" value="4000000">property>
bean>
@Test
public void testSingleton(){
ApplicationContext context = new ClassPathXmlApplicationContext("spring-scope.xml");
Car car = context.getBean("car", Car.class);
Car car1 = context.getBean("car", Car.class);
System.out.println(car == car1);
}//输出结果为true
<bean id="car" class="spring.life.Car" init-method="init" destroy-method="destroy">
<property name="brand" value="宝马"/>
<property name="price" value="450000"/>
bean>
package spring.life;
public class Car {
private String brand;
private Double price;
public Car() {
System.out.println("====>1、通过构造器创建bean对象");
}
/**
* 初始化方法
*/
public void init(){
System.out.println("====>3、调用bean的初始化方法");
}
/**
* 当IOC容器关闭的时候、调用bean的销毁方法
*/
public void destroy(){
System.out.println("====>5、调用bean的销毁方法");
}
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
System.out.println("====>2、通过set方法为bean的属性设置值");
}
public Double getPrice() {
return price;
}
public void setPrice(Double price) {
this.price = price;
}
@Override
public String toString() {
return "Car{" +
"brand='" + brand + '\'' +
", price=" + price +
'}';
}
public static void main(String[] args) {
ConfigurableApplicationContext context = new ClassPathXmlApplicationContext("spring-life.xml");
Car car = context.getBean("car", Car.class);
System.out.println("====>4、使用bean对象");
System.out.println(car);
//5、当IOC容器关闭的时候调用bean的销毁方法
context.close();
}
}
输出结果如下:
四月 20, 2019 12:26:22 上午 org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@7aec35a: startup date [Sat Apr 20 00:26:22 CST 2019]; root of context hierarchy
四月 20, 2019 12:26:22 上午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [spring-life.xml]
====>1、通过构造器创建bean对象
====>2、通过set方法为bean的属性设置值
postProcessBeforeInitialization
====>3、调用bean的初始化方法
postProcessAfterInitialization
====>4、使用bean对象
Car{brand='宝马', price=450000.0}
四月 20, 2019 12:26:22 上午 org.springframework.context.support.ClassPathXmlApplicationContext doClose
信息: Closing org.springframework.context.support.ClassPathXmlApplicationContext@7aec35a: startup date [Sat Apr 20 00:26:22 CST 2019]; root of context hierarchy
====>5、调用bean的销毁方法
bean的后置处理器
是对bean生命周期中的特定操作
package spring.life;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
/**
* bean的后置处理器
*/
public class MyBeanPostProcessor implements BeanPostProcessor {
/**
*在生命周期的二三步之间执行,对bean进行操作,需要返回一个bean
*/
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("postProcessBeforeInitialization");
return bean;
}
/**
*在生命周期的三四步之间执行,对bean进行操作,需要返回一个bean
*/
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("postProcessAfterInitialization");
return bean;
}
}
配置信息如下:
<bean class="spring.life.MyBeanPostProcessor">bean>
<bean id="car" class="spring.autowire.Car">
<property name="brand" value="奔驰"/>
<property name="price" value="500000"/>
bean>
<bean id="address" class="spring.autowire.Address">
<property name="province" value="天津"/>
<property name="city" value="天津"/>
bean>
<bean id="person" class="spring.autowire.Person" autowire="byType">
<property name="name" value="Tom"/>
bean>
<context:component-scan base-package="spring.annotation">
DAO层
@Repository
public class UserDaoJdbcImpl implements UserDao {
}
Service层
@Service
public class UserServiceImpl implements UserService {
}
Controller层
/**
* Controller注解的作用:
* 相当于在xml文件中:
*
* 注解默认的id值就是类名首字母小写,可以在注解中手动指定id值,:@Controller(value = "id值")可以简写为:@Controller("")
*/
@Controller
public class UserController {
}
测试:
@Test
public void testAnnotation(){
ApplicationContext context = new ClassPathXmlApplicationContext("spring-annotation.xml");
UserController userController = context.getBean("userController", UserController.class);
System.out.println(userController);
UserServiceImpl userServiceImpl = context.getBean("userServiceImpl", UserServiceImpl.class);
System.out.println(userServiceImpl);
UserDaoJdbcImpl userDaoJdbcImpl = context.getBean("userDaoJdbcImpl", UserDaoJdbcImpl.class);
System.out.println(userDaoJdbcImpl);
}
输出结果:
spring.annotation.controller.UserController@6328d34a
spring.annotation.service.UserServiceImpl@145eaa29
spring.annotation.dao.UserDaoJdbcImpl@15bb6bea
(1)context:include-filter子节点表示要包含的目标类
注意:通常需要与use-default-filters属性配合使用才能够达到“仅包含某些组件”这样的效果。即:通过将use-default-filters属性设置为false禁用默认过滤器,然后扫描的就只是include-filter中的规则指定的组件了。
第一种方法:
type=“annotation”:注解的全列名
--<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller">context:include-filter>
第二种方法:
type=“assignable”:类的全列名
<context:include-filter type="assignable" expression="spring.annotation.controller.UserController">context:include-filter>
use-default-filters=“true”,默认情况下就是true
第一种方法:type=“annotation”:注解的全列名
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller">context:exclude-filter>
第二种方法:
type=“assignable”:类的全列名
<context:exclude-filter type="assignable" expression="spring.annotation.controller.UserController">context:exclude-filter>
import org.springframework.stereotype.Repository;
@Repository
public class UserDaoJdbcImpl implements UserDao {
@Override
public void addUser() {
System.out.println("UserDao JDBC");
}
}
Service
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import spring.annotation.dao.UserDao;
@Service
public class UserServiceImpl implements UserService {
/**
* @Autowired工作机制 完成bean属性的自动装配
*
* 工作机制:首先使用byType的方式进行自动装配,如果能唯一匹配则装配成功
* 如果匹配到多个兼容类型的bean,那么会尝试使用byName的方式进行唯一确定,
* 如果能唯一确定,则装配成功,否则抛出异常。
*
* 默认情况下,使用@Autowired标注的属性必须装配,如果装配不了,则会抛出异常
* 可以使用required = false来设置不是必须装配
*
* 如果匹配到多个兼容类型的bean,则可以使用@Qualifier来进一步指定要装配的bean的id值
*
* @Autowired @Qualifier 注解既可以加到成员变量上还可以加到set方法上
*/
@Autowired(required = false)
@Qualifier("userDaoMybatisImpl")
private UserDao userDao;
// @Autowired(required = false)
// @Qualifier("userDaoMybatisImpl")
// public void setUserDao(UserDao userDao) {
// this.userDao = userDao;
// }
@Override
public void handle_addUser() {
userDao.addUser();
}
}
Controller
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import spring.annotation.service.UserService;
/**
* Controller注解的作用:
* 相当于在xml文件中:
*
* 注解默认的id值就是类名首字母小写,可以在注解中手动指定id值,:@Controller(value = "id值")可以简写为:@Controller("")
*/
@Controller
public class UserController {
@Autowired
private UserService userService;
public void regist(){
userService.handle_addUser();
}
}
测试方法:
@Test
public void testAnnotation2(){
ApplicationContext context = new ClassPathXmlApplicationContext("spring-annotation.xml");
UserController userController = context.getBean("userController", UserController.class);
userController.regist();
}