<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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">
<!--扫描com.woniu包及子包下的所有的类上是否有注解-->
<context:component-scan base-package="com.woniu" />
</beans>
Spring入门
Spring框架定义
Spring是分层JavaEE应用企业轻量级开源框架产品
两大核心特性: IOC和AOP
Spring各层提供解决方案: SpringMVC ,SpringJDBC,管理业务层事务,日志
SSM组合:
![image-20220616095501010](https://i-blog.csdnimg.cn/blog_migrate/ea5ef4f91fe8445b6eff6f4dd0cee0b6.png)
什么是IOC与优点
IOC - 控制反转
|-对象的调用者不用自己去创建该对象,而是由IOC容器统一提供,这种方式就称为控制反转
降低程序间的耦合
Spring实现IOC入门示例操作步骤
a. 依赖: spring-context
b. 添加spring核心配置文件 - applicationContext.xml
<beans>
<bean id="" class="">
</bean>
</beans>
c. 创建工厂对象
BeanFactory -Spring顶层工厂
|-子接口ApplicationContext 工厂对象
new ClassPathXMLApplcationContext(".xml")
d. 通过工厂对象获取bean对象 getBean("name")
上次作业 自定义IOC工厂练习
指定需要扫描注解的包
com.woniu.bean
|-类
@Component 元件,部件
已知一个包com.woniu.bean下分别有Tiger、Lion、Elephant三个Java源文件,请据此实现以下功能: [选做]
(1)自定义一个名为Component的注解,要求该注解只能用于类且代码运行时该注解依然有效;
(2)为Tiger和 Lion类添加Component注解(注:只写出类的结构和构造方法即可)
(3)在Application类中定义静态代码块,该代码块可自动将有Component注解修饰的类创建对象,并
放在Map集合中;
(4) 然后定义一个名为getBean的static方法,要求传入String beanName返回该名称对应的bean实例对象,如果没有找到
该beanName对应的实例对象,则引发NoSuchBeanDefinitionException自定义异常,
并提示“No qualifying bean avaliable !”
pack.name=com.woniu.bean
注解类:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Component {
String value() default "";
}
Bean实体类:
@Component("ele")
public class Elephant {
public Elephant() {
System.out.println("Elephant创建了...");
}
}
@Component
public class Lion {
public Lion() {
System.out.println("Lion创建...");
}
}
@Component("tiger")
public class Tiger {
public Tiger() {
System.out.println("Tiger创建了...");
}
}
工厂类Application
/**
* 工厂类
*/
public class Application {
private static Map<String,Object> map = new HashMap<>();
static {
try {
/*
该代码块可自动将有Component注解修饰的类创建对象,
并放在Map集合中
*/
Properties props = new Properties();
InputStream inStream = Application.class.getClassLoader().getResourceAsStream("pack.properties");
props.load(inStream);
inStream.close();
//获取配置包名
String packName = props.getProperty("pack.name");
//获取指定包下所有class文件 - 获取当前应用程序的class文件的根路径
File classRootPath =new File(Application.class.getResource("/").toURI());
//将包名修改为 路径名
String packPath = packName.replace(".","\\");
File targetPath = new File(classRootPath.getPath()+"\\"+packPath);
File[] classFile = targetPath.listFiles(); //获取bean包下的所有类文件
for (File file : classFile) {
String fileName = file.getName();
String className = fileName.replace(".class","");
Class clazz = Class.forName(packName+"."+className); //获取类名对应的Class对象
if(clazz.isAnnotationPresent(Component.class)){
//获取类上的注解对象信息
Component component = (Component) clazz.getDeclaredAnnotation(Component.class);
String beanName = component.value();
if("".equals(beanName)){
beanName = className.substring(0,1).toLowerCase()+className.substring(1);
}
//将bean对象存放容器中
map.put(beanName,clazz.newInstance());
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static Object getBean(String name){
Object bean = map.get(name);
if(bean==null){
throw new NoSuchBeanDefinitionException("No qualifying bean avaliable!");
}
return bean;
}
public static void main(String[] args) {
Tiger tiger =(Tiger)Application.getBean("tiger");
System.out.println(tiger);
Lion lion =(Lion)Application.getBean("lion");
System.out.println(lion);
Elephant elephant =(Elephant) Application.getBean("ele");
System.out.println(elephant);
}
}
2.Spring入门-补充
2-1 Spring工厂类结构体系
BeanFactory属于Spring顶层工厂接口 [平时开发不使用]
|- ApplicationContext工厂接口 --常用的
ClassPathXmlApplicationContext:
|-它是从类的根路径下加载配置文件,推荐使用这种 /resources 目录
FileSystemXmlApplicationContext: [一般不使用]
|-它是从磁盘路径上加载配置文件,配置文件可以在磁盘的任意位置。
AnnotationConfigApplicationContext: 基于注解配置来创建的工厂对象
|-当我们使用注解配置容器对象时,需要使用此类来创建 spring 容器。它用来读取注解
2-2 BeanFactory与AppicationContext区别
BeanFactory和ApplicationContext是Spring的两大核心接口,都可以当做Spring的容器。其中ApplicationContext是BeanFactory的子接口
区别:
applcationContext具有BeanFactory不具备功能:
a. AOP特性
b. web应用功能支持
c. 加载Bean的区别
细节区别:
BeanFactroy采用的是延迟加载形式来注入Bean
|-启动程序,读取配置文件,但并不创建对象,并存入容器
|-只有在访问对象时,才去创建
applcationContext 采用的是即时加载,也就是在启动程序时,读取配置,创建对象,并存入容器
3 Spring-IOC-2
3-1 Bean的管理
a.bean的作用域范围
bean的scope属性用于指定bean的范围
|-singleton 单例 [默认值]
|-prototype 多例
1、singleton :默认值,单例的.
2、prototype :多例的.
3、request :WEB 项目中,Spring 创建一个 Bean 的对象,将对象存入到 request 域中
4、session :WEB 项目中,Spring 创建一个 Bean 的对象,将对象存入到 session 域中.
5、global session :WEB 项目中,应用在 Portlet 环境 .如果没有 Portlet 环境那么 globalSession 相当于 session.
public void testAddUser(){
//创建工厂Bean对象
//BeanFactory ac = new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
System.out.println("==============================================================");
UserService userService1 = (UserService)ac.getBean("userService");
UserService userService2 = (UserService)ac.getBean("userService");
System.out.println(userService1==userService2);
userService1.addUser();
}
b.bean生命周期 - 重点
分为单例与多例讨论:
Singleton单例:
一个应用只有一个对象的实例。它的作用范围就是整个应用
出生: 创建容器时
活着: 容器存在,对象存在
死亡: 容器销毁时,对象消失
prototype多例:
出生: 当使用对象时,创建新的对象实例
活着: 只要对象在使用中,就一直活着
死亡: 对象不再使用时,由GC垃圾回收器来回收
|-不是由容器来维护和管理
示例:
/**
* 用户业务实现类
*/
public class UserServiceImpl implements UserService {
//创建数据层对象
private UserDao userDao;
public void addUser() {
//执行数据操作方法
userDao.save();
}
public UserDao getUserDao() {
return userDao;
}
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void init(){
System.out.println("userService对象初始化...");
}
public void destroy(){
System.out.println("userService对象销毁....");
}
}
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="userDao" class="com.woniu.dao.impl.UserDaoImpl" scope="prototype"/>
<bean id="userService" class="com.woniu.service.impl.UserServiceImpl"
scope="prototype" init-method="init" destroy-method="destroy">
<!--依赖注入 使用setter -->
<property name="userDao" ref="userDao" />
</bean>
</beans>
测试业务类:
/**
* 业务测试类 --模拟表示层
*/
public class UserServiceTest {
@Test
public void testAddUser(){
//创建工厂Bean对象
//BeanFactory ac = new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));
ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
System.out.println("==============================================================");
UserService userService1 = (UserService)ac.getBean("userService");
// UserService userService2 = (UserService)ac.getBean("userService");
// System.out.println(userService1==userService2);
userService1.addUser();
//关闭容器
ac.close();
}
}
c.实例化bean的三种方式 -- 了解
方式一: 使用默认构造器 -- 常用
<bean id="userDao" class="com.woniu.dao.impl.UserDaoImpl"/>
方式二: 静态工厂方式创建方式
<!--bean的id标识的对象由StaticFactory 工厂类中的静态方法getUserDao()来提供-->
<bean id="userDao" class="com.woniu.factory.StaticFactory" factory-method="getUserDao"/>
示例代码:
/**
* 静态工厂类
*/
public class StaticFactory {
/**
* 静态工厂方法
* @return
*/
public static UserDao getUserDao(){
return new UserDaoImpl();
}
}
方式三: 实例工厂创建对象方式
/**
* 实例工厂类
*/
public class InstanceFactory {
/**
* 实例工厂方法
* @return
*/
public UserDao getUserDao(){
return new UserDaoImpl();
}
}
<!--创建实例工厂Bean对象-->
<bean id="instanceFactoryBean" class="com.woniu.factory.InstanceFactory" />
<!--指定实例的工厂bean对象及工厂方法,创建UserDao对象-->
<bean id="userDao" factory-bean="instanceFactoryBean" factory-method="getUserDao" />
小结:
方式二和方式三适用于,引用第三方jar中的类来创建对象时,如果该类中没有默认无参构造器时可以使用
还有像Calendar这样类似的抽象类,不能直接通过构造器创建对象,但是提供了静态方法创建实例
JDK--> java.util.Calendar类
<bean id="cal" class="java.util.Calendar" factory-method="getInstance" />
3-2 依赖注入
DI - Dependency Injection 依赖注入 - IOC的实现方式
比如: UserServiceImpl --> UserDao对象
依赖注入的方式:
(1). setter注入
public class UserServiceImpl implements UserService {
//创建数据层对象
private UserDao userDao;
public UserDao getUserDao() {
return userDao;
}
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
...
}
配置setter的依赖注入:
<bean id="userDao" class="com.woniu.dao.impl.UserDaoImpl" />
<bean id="userService" class="com.woniu.service.impl.UserServiceImpl">
<!--依赖注入 使用setter -->
<property name="userDao" ref="userDao" />
</bean>
(2) 构造器注入
public class UserServiceImpl implements UserService {
//创建数据层对象
private UserDao userDao;
private String name;
private Integer age;
private Date birthday;
public UserServiceImpl() {
}
public UserServiceImpl(UserDao userDao) {
this.userDao = userDao;
}
public UserServiceImpl(String name, Integer age, Date birthday) {
this.name = name;
this.age = age;
this.birthday = birthday;
}
涉及的标签:
constructor-arg
属性:
index:指定参数在构造函数参数列表的索引位置
type:指定参数在构造函数中的数据类型
name:指定参数在构造函数中的名称 用这个来找给谁赋值
value:它能赋的值是基本数据类型和 String 类型
ref:它能赋的值是其他 bean 类型,也就是说,必须得是在配置文件中配置过的 bean
配置构造器注入:
<bean id="userDao" class="com.woniu.dao.impl.UserDaoImpl" />
<bean id="userService" class="com.woniu.service.impl.UserServiceImpl">
<constructor-arg name="userDao" ref="userDao" />
</bean>
-----------------------------------------------------------------
<bean id="now" class="java.util.Date" />
<bean id="userService" class="com.woniu.service.impl.UserServiceImpl">
<!--<constructor-arg name="userDao" ref="userDao" />-->
<constructor-arg index="0" value="Jack" />
<constructor-arg index="1" value="20" />
<constructor-arg name="birthday" ref="now" />
</bean>
(3) p和c命名空间注入
添加p命名空间-- 本质上也是setter注入
<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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="userDao" class="com.woniu.dao.impl.UserDaoImpl" />
<bean id="userService" class="com.woniu.service.impl.UserServiceImpl" p:userDao-ref="userDao">
</bean>
c-命名空间 -- Constructor注入的简写
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:c="http://www.springframework.org/schema/c"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="now" class="java.util.Date" />
<bean id="userService" class="com.woniu.service.impl.UserServiceImpl" c:_0="Tom" c:_1="21" c:_2-ref="now">
</bean>
(4) 集合属性的注入 - [了解]
Array,List为例
如果我们的Bean类属性是数组或集合 [List, set, Map,Properties]
public class Bean {
private String[] arr;
private List<String> strList;
private List<User> userList;
private Map<String,User> map;
public void print(){
System.out.println("--------------------------Array--------------------");
for(String s : arr){
System.out.println(s);
}
System.out.println("--------------------------StrList--------------------");
for(String s : strList){
System.out.println(s);
}
System.out.println("----------------UserList------------------------");
for(User u : userList){
System.out.println(u);
}
}
...
}
配置注入:
<bean id="userBean" class="com.woniu.entity.User">
<property name="name" value="Mike" />
<property name="age" value="22" />
</bean>
<bean id="bean" class="com.woniu.bean.Bean">
<!--方式一: 为数组属性注入值-->
<!--<property name="arr" value="aaa,bbb,ccc" />-->
<!--方式二: 使用array -->
<property name="arr">
<array>
<value>xxx</value>
<value>yyy</value>
<value>zzz</value>
</array>
</property>
<property name="strList">
<list>
<value>111</value>
<value>222</value>
<value>333</value>
</list>
</property>
<property name="userList">
<list>
<bean class="com.woniu.entity.User">
<property name="name" value="Jack" />
<property name="age" value="24" />
</bean>
<ref bean="userBean" />
<ref bean="userBean" />
</list>
</property>
</bean>
4. Spring - 注解
4-1 基于注解实现springIOC
(1) Spring注解的背景
Spring1.x 时代,基于XML配置时代,缺点:
xml文件将会十分庞大,拆分后xml会非常多,可读性与可维护性变得很低
.java文件和.xml文件之间不断切换,影响开发效率
为了解决这两个问题,Spring引入了注解,通过"@XXX"的方式,让注解与Java Bean紧密结合,既大大减少了配置文件的体积,又增加了Java Bean的可读性与内聚性
(2) 常用的IOC配置-注解
前提: 要使用Spring注解完成IOC配置,首先要开启Spring自动检测bean的配置。
或者说是: 开启Spring注解扫描的功能
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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">
<!--扫描com.woniu包及子包下的所有的类上是否有注解-->
<context:component-scan base-package="com.woniu" />
</beans>
@Component 组件注解
//如果不指定Component注解的成员属性值,则默认使用类名首字母小写作为bean的名称
@Component
public class UserDaoImpl implements UserDao {
...
}
等价于xml:
<bean id="userDao" class="com.woniu.dao.impl.UserDaoImpl" />
@Resource 属性注入注解
/**
* 用户业务实现类
*/
@Component("userService")
public class UserServiceImpl implements UserService {
//创建数据层对象
@Resource(name="userDaoImpl") //注解作用是将容器中的name为userDao对象注入到属性userDao
private UserDao userDao;
...
}
(3) 常用的其他几个注解
效果等同于 @Component :语义注解
@Controller @Service @Repository 分层语义注解
这三个注解都是针对第一个的衍生注解,他们的作用级属性都是一模一样。不过提供了更加明确的语义化。
@Controller:一般用于表现层的注解。即SpringMVC中
@Service:一般用于业务层的注解。
@Repository:一般用于持久层的注解
-------------------------------如果创建bean对象不属于三层中的任一层,则使用@Component注解
@Autowired 自动装配
自动按类型进行注入,可以省略setter
当有多个同类型的bean相匹配时,则默认根据属性名进行注入,也可以指定@Qualifier注解指定bean的名称进入注入,否则会报错
另外,可以指定成员属性required=false ,避免因找不到bean而报错,使用null值
@Autowired与@Resurce区别 ?
相当于:<property name="" ref="">
区别1:
@Autowired [常用] - 默认按照属性类型注入
@Resource -默认按属性名称注入 -- name="xxx"
区别2:
@Autowired 属于Spring框架提供
@Resource由javaEE提供的注解
共同点:
使用时,都可以将类中的 setter访问器省略
@Qualifier 指定容器中的bean名称进行注入
在自动按照类型注入的基础之上,再按照 Bean 的 id 注入。它在给字段注入时不能独立使用,必须和@Autowire 一起使用;但是给方法参数注入时,可以独立使用。
@Value 为基本类型数据注入值
作用:
注入基本数据类型和String 类型数据的
@Value(“tom”)
private String usename;
示例代码:
@Service("userService")
public class UserServiceImpl implements UserService {
//创建数据层对象
@Resource(name="userDaoImpl") //注解作用是将容器中的name为userDao对象注入到属性userDao
// @Autowired(required = false)
// @Qualifier("userDaoImpl3")
private UserDao userDao; //如果为false,注入时未能找到,则为null
public void addUser() {
userDao.save();
}
}