Spring
Spring是轻量级开源框架,可以降低开发应用程序的复杂度,可以集成其他框架,它的核心是控制反转IOC容器和面向切面AOP,控制反转IOC容器底层是xml配置文件 + 工厂模式 + 反射,实现控制反转IOC容器有两个接口,一是BeanFactory,是spring内部成员使用的,二是ApplicationContext,这是BeanFactory的子接口,在BeanFactory的基础上扩展了新的功能,更适合开发人员使用,IOC容器负责两个功能,一个是创建对象和管理对象的生命周期,创建对象有两种方式,一是通过xml配置文件,二是通过注解的方式,另一个是依赖注入,也就是注入属性,有两种方式,一是set方法注入,二是构造器注入,面向切面AOP的功能是在不修改源代码的情况下,对方法添加新的功能,实现AOP有两个动态代理对象,如果实现了接口使用JDK动态代理,如果没有实现接口,使用cglib动态代理,aop有个重要概念,分别是连接点,切入点,通知,切面,连接点是指类中所有需要添加功能的方法,这些方法就是连接点,切入点是类中指实际添功能的方法,这些方法就是切入点,通知是指方法中新添加功能的代码,这些代码就是通知,切面是指将通知添加到方法的过程就是切面
下载springH5的jar包,过程是:
1.进入官网,https://spring.io/,点击右边小猫咪图标
2.找到Access to Binaries描述下的链接
3.找到Downloading a Distribution下的链接https://repo.spring.io/ui/
4.点击左侧Artifacts,找到release下的org下的springframework下的spring
5.复制右侧的url,https://repo.spring.io/artifactory/release/org/springframework/spring/
6.打开下载网址,滑到最下面下载最新版本spring的jar包即可
创建项目,导入五个核心jar包:
创建实体类,用于测试用spring框架创建对象来调用方法:
public class User {
public void add(){
System.out.println("add方法被调用了......");
}
}
创建spring配置文件,new…找到spring config:
<?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">
<!--spring通过反射技术创建user对象,并且取名叫user-->
<bean id="user" class="com.alibaba.User"></bean>
</beans>
创建测试类:
public class UserTset {
@Test
public void testAdd(){
//1.读取配置文件
ApplicationContext bean = new ClassPathXmlApplicationContext("bean.xml");
//2.获取配置创建的对象
User user = bean.getBean("user", User.class);
//3.调用方法
user.add();
}
}
---------------------------------------------------------
控制反转IOC容器:
控制反转:将创建对象和管理对象生命周期的权限交给spring管理,目的是为了降低程序的耦合度,提高程序的扩展力
IOC的底层就是对象工厂,底层原理:xml配置文件,工厂模式,反射
IOC实现步骤:
1.xml配置文件配置需要创建的对象
2.创建对象工厂类,通过反射创建对象
spring实现IOC容器的两个接口:
1.BeanFactory,是spring内部使用的接口,开发人员一般不用,这个接口在读取配置文件的时候不会创建配置的对象,在获取对象的时候才创建配置的对象
2.ApplicationContext,是BeanFactory的子接口,扩展了更多的功能,开发人员使用!该接口在读取配置文件的时候就会创建配置的对象
ApplicationContext接口两个实现类:
1.FileSystemXmlApplicationContext,需要传入xml配置文件的全路径
2.ClassPathXmlApplicationContext,只需要传入xml配置文件名xx.xml
IOC操作Bean管理:
1.spring创建对象
2.spring注入属性,DI依赖注入,就是注入属性,spring支持set方法注入和构造器方式注入
Bean管理操作有两种方式:
1.xml配置文件
2.注解
xml方式
实现set方法注入属性:
编写类,属性,提供set方法
public class User {
private String name;
private int age;
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
}
配置spring config配置文件
<?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">
<!--spring通过反射技术创建user对象,并且取名叫user-->
<bean id="user" class="com.alibaba.User">
<!--注入属性前,必须先配置要创建的对象-->
<property name="name" value="张三"></property>
<property name="age" value="18"></property>
</bean>
</beans>
测试结果
public class UserTset {
@Test
public void testAdd() {
//1.读取配置文件
ApplicationContext bean = new ClassPathXmlApplicationContext("bean.xml");
//2.获取配置创建的对象
User user = bean.getBean("user", User.class);
System.out.println(user);
}
}
--------------构造器方式注入--------------------
创建对象,提供属性构造器
public class User {
private String name;
private int age;
//构造器方式注入
public User(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
配置spring config配置文件
<?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">
<!--spring通过反射技术创建user对象,并且取名叫user-->
<bean id="user" class="com.alibaba.User">
<!--注入的是全参构造器赋值-->
<constructor-arg name="name" value="李四"></constructor-arg>
<constructor-arg name="age" value="19"></constructor-arg>
</bean>
</beans>
测试结果
public class UserTset {
@Test
public void testAdd() {
//1.读取配置文件
ApplicationContext bean = new ClassPathXmlApplicationContext("bean.xml");
//2.获取配置创建的对象
User user = bean.getBean("user", User.class);
System.out.println(user);
}
}
----------------属性是null值或者含有其他特殊符号-----------------
spring config配置文件赋值是null或含有其他特殊符号处理方法:
<?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">
<!--spring通过反射技术创建user对象,并且取名叫user-->
<bean id="user" class="com.alibaba.User">
<!--注入的是全参构造器赋值-->
<property name="name">
<!--赋值为null-->
<null/>
</property>
<property name="age">
<!--想要属性包含特殊符号,比如<>-->
<!--方式1:用转义方法,比如>表示大于,<表示小于-->
<!--方式2:用语法,<![CDATA[内容]]>-->
<value>
<![CDATA[19]]>
</value>
</property>
</bean>
</beans>
-------------------注入外部bean----------------------
定义dao层接口
package com.alibaba.dao;
public interface UserDao {
public void method();
}
定义dao层接口实现类
public class UserDaoImpI implements UserDao {
public void method() {
System.out.println("UserDaoImpI implements method!!!");
}
}
定义业务层service类,引入外部bean
public class UserService {
//注入外部bean属性
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void methode(){
System.out.println("UserService method!!!");
userDao.method();
}
}
配置spring config配置文件
<?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="userDaoImpI" class="com.alibaba.dao.UserDaoImpI"></bean>
<bean id="userService" class="com.alibaba.service.UserService">
<!--ref:表示引入其他对象,这里是UserDaoImpI对象的ID-->
<property name="userDao" ref="userDaoImpI"></property>
</bean>
</beans>
测试结果
@Test
public void testAdd() {
//1.读取配置文件
ApplicationContext bean = new ClassPathXmlApplicationContext("bean.xml");
//2.获取配置创建的对象
UserService userService = bean.getBean("userService", UserService.class);
userService.methode();
}
--------------------注入内部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 name;//员工名
private int age;//员工年龄
private Dept dept;//引入部门类
public void setDept(Dept dept) {
this.dept = dept;
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Emp{" +
"name='" + name + '\'' +
", age=" + age +
", dept=" + dept +
'}';
}
}
spring config配置文件
<?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="emp" class="com.alibaba.bean.Emp">
<property name="name" value="张三"></property>
<property name="age" value="20"></property>
<property name="dept" >
<!--内部Bean-->
<bean id="dept" class="com.alibaba.bean.Dept">
<property name="dname" value="无垢者"></property>
</bean>
</property>
</bean>
</beans>
-------------------------------------------
还可以使用级联方式:外部bean
<?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="emp" class="com.alibaba.bean.Emp">
<property name="name" value="张三"></property>
<property name="age" value="20"></property>
<property name="dept" ref="dept"></property>
</bean>
<!--外部Bean-->
<bean id="dept" class="com.alibaba.bean.Dept">
<property name="dname" value="无垢者"></property>
</bean>
</beans>
测试结果
public class UserTset {
@Test
public void testAdd() {
//1.读取配置文件
ApplicationContext bean = new ClassPathXmlApplicationContext("bean.xml");
//2.获取配置创建的对象
Emp emp = bean.getBean("emp", Emp.class);
System.out.println(emp);
}
}
-------------注入集合---------------------
创建类,属性是集合,提供set方法和toString
public class Controller {
private String[] arr;
private List<String> list;
private Set<String> set;
private Map<String,String> map;
public void setArr(String[] arr) {
this.arr = arr;
}
public void setList(List<String> list) {
this.list = list;
}
public void setSet(Set<String> set) {
this.set = set;
}
public void setMap(Map<String, String> map) {
this.map = map;
}
@Override
public String toString() {
return "Controller{" +
"arr=" + Arrays.toString(arr) +
", list=" + list +
", set=" + set +
", map=" + map +
'}';
}
}
spring config配置文件
<?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="controller" class="com.alibaba.Controller">
<!--赋值数组-->
<property name="arr">
<array>
<value>arr1</value>
<value>arr2</value>
</array>
</property>
<!--赋值List集合-->
<property name="list">
<list>
<value>list1</value>
<value>list2</value>
</list>
</property>
<!--赋值Set集合-->
<property name="set">
<set>
<value>set1</value>
<value>set2</value>
</set>
</property>
<!--赋值Map集合-->
<property name="map">
<map>
<entry key="1号" value="张三"></entry>
<entry key="2号" value="李四"></entry>
</map>
</property>
</bean>
</beans>
测试结果
@Test
public void testAdd() {
//1.读取配置文件
ApplicationContext bean = new ClassPathXmlApplicationContext("bean.xml");
//2.获取配置创建的对象
Controller controller = bean.getBean("controller", Controller.class);
System.out.println(controller);
}
-------------注入的集合,存储的值是对象----------------------
创建类
public class Collection_Bean {
private List<User> users;
public void setUsers(List<User> users) {
this.users = users;
}
@Override
public String toString() {
return "Collection_Bean{" +
"users=" + users +
'}';
}
}
spring config配置文件
<?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="collection_bean" class="com.alibaba.bean.Collection_Bean">
<property name="users">
<list>
<!--引入外部bean对象-->
<ref bean="user"></ref>
</list>
</property>
</bean>
<bean id="user" class="com.alibaba.User">
<property name="name" value="张三"></property>
<property name="age" value="18"></property>
</bean>
</beans>
测试结果
@Test
public void testAdd() {
//1.读取配置文件
ApplicationContext bean = new ClassPathXmlApplicationContext("bean.xml");
//2.获取配置创建的对象
Collection_Bean collection_Bean = bean.getBean("collection_bean", Collection_Bean.class);
System.out.println(collection_Bean);
}
-------------将集合注入部分提取出来------------------
1.增加新的约束文件内容,复制一份xmlns=“http://www.springframework.org/schema/beans”
修改成xmlns:util=“http://www.springframework.org/schema/util”
复制一份 xsi:schemaLocation,将所有beans改成util
“http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd”>
最终结果如下:
<?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: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-util.xsd">
2.通过util标签完成list集合注入的提取
<!--提取list集合注入的属性-->
<util:list id="user">
<!--如果是对象,用<ref bean=""></ref>-->
<value>张三</value>
</util:list>
完整顺序:
创建类
public class Collection_Bean {
private List<String> name;
@Override
public String toString() {
return "Collection_Bean{" +
"name=" + name +
'}';
}
public void setName(List<String> name) {
this.name = name;
}
}
spring config配置文件
<?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: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-util.xsd">
<!--提取list集合注入的属性-->
<util:list id="user">
<!--如果是对象,用<ref bean=""></ref>-->
<value>张三</value>
</util:list>
<bean id="collection_bean" class="com.alibaba.bean.Collection_Bean">
<property name="name" ref="user"></property>
</bean>
</beans>
测试结果
@Test
public void testAdd() {
//1.读取配置文件
ApplicationContext bean = new ClassPathXmlApplicationContext("bean.xml");
//2.获取配置创建的对象
Collection_Bean collection_Bean = bean.getBean("collection_bean", Collection_Bean.class);
System.out.println(collection_Bean);
}
------------------------------------------------------------
IOC操作Bean管理
有两种类型Bean,一种的普通bean,一种是工厂bean
普通bean:spring config配置文件定义的类就是返回值的类型
工厂bean:config配置文件定义的类返回值类型可以不一样
工厂bean步骤:
1.创建类,让类作为工厂bean,实现接口FactoryBean,泛型约束类型
2.实现接口的方法,定义getObject方法返回值为泛型约束类型
创建类,实现FactoryBean接口
public class MyBean implements FactoryBean<User> {
/**
* 返回值类型可以改变
* @return
* @throws Exception
*/
public User getObject() throws Exception {
User user = new User();
user.setName("张三");
user.setAge(18);
return user;
}
public Class<?> getObjectType() {
return null;
}
public boolean isSingleton() {
return false;
}
}
spring config配置文件
<?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: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-util.xsd">
<bean id="myBean" class="com.alibaba.bean.MyBean"></bean>
</beans>
测试结果
@Test
public void testAdd() {
//1.读取配置文件
ApplicationContext bean = new ClassPathXmlApplicationContext("bean.xml");
//2.获取配置创建的对象
User myBean = bean.getBean("myBean", User.class);
System.out.println(myBean);
}
-----------------------------------------------------
bean的作用域:
spring默认是单实例,可以设置成多实例
将pring默认单实例改成多实例:
加属性scope=prototype即可
如果是单实例,在读取配置文件就会创建对象
如果是多实例,在读取配置文件不会创建对象,而是调用getBean的时候创建多实例对象
bean生命周期:
1.执行无参构造器创建bean实例
2.调用set方法赋值
3.将bean实例传递给后置处理器的方法
4.执行初始化方法,需要配置
5.将bean实例传递给后置处理器的方法
6.获取创建好的bean实例
7.执行销毁方法,需要配置
代码演示bean生命周期:
创建类
public class MyBean {
private String name;
public MyBean() {
System.out.println("第一步,执行无参构造器创建bean实例");
}
public void setName(String name) {
this.name = name;
System.out.println("第二步,调用set方法为属性赋值");
}
public void initMethod(){
System.out.println("第四步,执行初始化方法");
}
public void destroyMethod(){
System.out.println("第七步,执行销毁方法");
}
}
后置处理器实现类:
public class BeanPostProcessorImpI implements BeanPostProcessor {
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("第3步,初始化之前执行的后置处理器方法");
return bean;
}
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("第5步,初始化之后执行的后置处理器方法");
return bean;
}
}
spring config配置文件
<?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: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-util.xsd">
<!--init-method:配置初始化方法,destroy-method配置销毁方法-->
<bean id="myBean" class="com.alibaba.lifecycle.MyBean" init-method="initMethod" destroy-method="destroyMethod">
<property name="name" value="张三"></property>
</bean>
<!--配置后置处理器:会对所有bean生效-->
<bean id="beanPostProcessorImpI" class="com.alibaba.lifecycle.BeanPostProcessorImpI"></bean>
</beans>
测试类
@Test
public void testAdd() {
//1.读取配置文件
ApplicationContext bean = new ClassPathXmlApplicationContext("bean.xml");
//2.获取配置创建的对象
MyBean myBean = bean.getBean("myBean", MyBean.class);
System.out.println("第六步,获取创建好的bean实例");
//最后需要手动销毁
myBean.destroyMethod();
}
--------------------------属性自动装配--------------------------------
主要是配置文件的改变,byName表示id属性名必须和注入的属性名相同,byType表示类型必须相同!
<?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: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-util.xsd">
<bean id="dept" class="com.alibaba.bean.Dept">
<property name="dname" value="杀神部"></property>
</bean>
<!--autowire:spring根据属性名进行自动装配,要求:id属性名必须和注入的属性名相同-->
<bean id="emp" class="com.alibaba.bean.Emp" autowire="byName">
<property name="name" value="张三"></property>
<property name="age" value="18"></property>
</bean>
</beans>
----------------------------------------------------
引入外部属性文件,比如数据库连接信息:
1.添加约束文件的命名空间
xmlns:context="http://www.springframework.org/schema/context"以及http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
2.使用标签,引入外部属性文件
<context:property-placeholder location=“dataSource.properties”></context:property-placeholder>
3.配置需要创建的对象,引入第三方jar包的对象,省略不做…
使用${属性配置文件的key}赋值
这样只需要修改属性配置文件,spring config配置文件不需要修改!
注解
注解是代码特殊标记,可以简化xml配置
创建对象的注解有四个:
@Component,@Controller,@Service,@Repository
基于注解完成对象创建的步骤:
1.添加aop依赖jar包
2.引入约束文件的名称空间,配置组件扫描
3.创建类
4.创建测试类
1.添加aop依赖jar包,spring其他核心依赖也需要,否则无法修改约束文件
<!--AOP依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.3.16</version>
</dependency>
2.引入约束文件的名称空间,配置组件扫描
<?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: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">
<!--配置组件扫描-->
<context:component-scan base-package="com.alibaba.spring5"></context:component-scan>
</beans>
3.创建类
package com.alibaba.spring5.service;
import org.springframework.stereotype.Component;
//创建对象注解的(value = "user")可以省略不写,对象引用默认是类名首字母小写
//如果想取名,value属性可以省略,直接写@Component("xxx")
@Component(value = "user")
public class User {
public void method(){
System.out.println("method方法执行了!");
}
}
4.创建测试类
@Test
public void testMethod(){
//1.读取配置文件,创建对象
ApplicationContext bean = new ClassPathXmlApplicationContext("springannotation.xml");
//2.获取创建好的对象
User user = bean.getBean("user", User.class);
//3.调用方法测试结果
user.method();
}
--------------------------------------------------------------------
基于注解方式实现属性注入
@AutoWired:根据属性类型自动装配
@Qualifier:根据属性名注入,必须联合AutoWired使用,当注入的接口属性有多个实现类,用来指定注入的对象!
@Resource:根据类型注入,也可以根据属性名注入
以上三个是针对对象类型的属性注入
@Value:是对普通属性的注入
创建持久层接口:
public interface UserDao {
public void method();
}
创建接口实现类:
@Repository
public class UserDaoImp implements UserDao {
public void method() {
System.out.println("我是UserDao实现类的方法!");
}
}
创建业务层类,注入对象属性:
@Component
public class UserService {
@Autowired
private UserDao userDao;//多态,相当于 UserDao userDao = new UserDaoImp();
public void method(){
System.out.println("method方法执行了!");
//调用方法
userDao.method();
}
}
测试结果:
@Test
public void testMethod(){
//1.读取配置文件,创建对象
ApplicationContext bean = new ClassPathXmlApplicationContext("springannotation.xml");
//2.获取创建好的对象
UserService user = bean.getBean("user", UserService.class);
//3.调用方法测试结果
user.method();
}
测试QUA注解:
@Component
public class UserService {
@Autowired
@Qualifier("userDaoImp")//注入对象名为userDaoImp的对象
private UserDao userDao;//多态,相当于 UserDao userDao = new UserDaoImp();
public void method(){
System.out.println("method方法执行了!");
//调用方法
userDao.method();
}
}
测试Resource注解:它是javax包下扩展的,不属于spring的,虽然也能做到相同的注入功能,但是spring推荐使用自家的产品
@Component
public class UserService {
//@Resource//根据对象类型注入
@Resource(name = "userDaoImp")//根据对象名注入
private UserDao userDao;//多态,相当于 UserDao userDao = new UserDaoImp();
public void method(){
System.out.println("method方法执行了!");
//调用方法
userDao.method();
}
}
测试Value注解:
//@Value(value = "张三")
@Value("张三")
private String name;//用注解注入普通属性
-----------------------------------------------
完全用注解开发
第一步:创建配置类
@Configuration//表示这是一个配置类
@ComponentScan(basePackages = "com.alibaba.spring5")//表示扫描该包下所有对象
public class SpringConfig {
}
第二步,将扫描配置文件对象修改成配置类对象,测试结果
@Test
public void testMethod(){
//1.创建注解类读取配置类
ApplicationContext bean = new AnnotationConfigApplicationContext(SpringConfig.class);
//2.获取创建好的对象
UserService user = bean.getBean("userService", UserService.class);
//3.调用方法测试结果
user.method();
}
AOP
AOP面向切面:
在不修改源代码的情况下,添加新的功能,降低程序的耦合度,提高程序的扩展性
AOP底层原理:
使用了动态代理,有两种动态代理方式
1.有接口的情况,使用了JDK动态代理,创建了接口实现类的代理对象,增加新的功能
2.没有接口的情况,CGLIB动态代理,创建子类代理对象,增加新的功能
JDK动态代理底层原理实现过程:
定义接口
public interface UserDao {
public int method(int a,int b);
}
定义接口实现类
public class UserDaoImp implements UserDao {
public int method(int a, int b) {
System.out.println("我是UserDao实现类的方法!");
return a + b;
}
}
使用JDK动态代理,为对象的方法增加新的功能
//JDK代理类
public class JDKProxy {
public static void main(String[] args) {
//创建接口实现类代理对象
Class[] interfaces = {UserDao.class};
UserDaoProxy userDaoProxy = new UserDaoProxy(new UserDaoImp());
UserDao o = (UserDao) Proxy.newProxyInstance(UserDao.class.getClassLoader(), interfaces, userDaoProxy);
int result = o.method(1, 2);
System.out.println("result = " + result);
}
}
//创建代理对象的代码
class UserDaoProxy implements InvocationHandler {
//需要将被代理的对象传递过来,通俗的说就是哪个对象的方法需要增加新的功能,传递过来
//使用构造器传递
private Object obj;//用Object的目的是:多态,更通用
public UserDaoProxy(Object obj) {
this.obj = obj;
}
//增加功能的方法
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//新增的功能在方法之前
System.out.println("新增的功能在方法之前!");
//执行新增的方法
Object invoke = method.invoke(obj, args);
//新增的功能在方法之前
System.out.println("新增的功能在方法之后!");
return invoke;
}
}
-------------------------------------------------------
AOP的术语概念:
连接点:类中可以增加功能的方法,这些方法就是连接点
切入点:实际被增加功能的方法,这些方法就是切入点
通知:方法中实际增加功能的部分逻辑就是通知,通知有多种类型,分别是:前置通知,后置通知,环绕通知,异常通知,最终通知
切面:是一个动作,将通知加入切入点的过程
Spring框架一般是基于AspectJ实现AOP操作:
AspectJ:是独立框架,不属于Spring,只是联合使用进行AOP操作
AspectJ实现AOP有两种方式:1.xml配置文件2.注解
添加依赖
切入点表达式:
语法结构:
execution(权限修饰符,返回值类型,全类名,方法名(参数列表))
例子1:需要对com.alibaba.spring5.service.User类下的method方法增加新的功能
execution(* com.alibaba.spring5.service.User.method(…))
解释:表示通用返回值类型,中间有个空格,权限修饰符可以省略不写,点点表示参数
例子2:需要对com.alibaba.spring5.service.User类下的所有方法增加新的功能
execution( com.alibaba.spring5.service.User.(…))
例子3:需要对com.alibaba.spring5.servicer包下的所有类的所有方法增加新的功能
execution( com.alibaba.spring5.service.*.*(…))
进行通知的配置:
1.在spring config配置文件中添加新的约束,开启注解扫描
<?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:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--开启组件扫描-->
<context:component-scan base-package="com.alibaba.spring5.aopanno"></context:component-scan>
</beans>
2.使用注解创建User和UserProxy对象
//被增强类
@Component
public class User {
public void method() {
System.out.println("method方法执行了!");
}
}
-------------------------------
//增强类
@Component
public class UserProxy {
//在方法执行前,增加了新的功能
public void before() {
System.out.println("before方法执行了......");
}
}
3.在增强类上面添加注解Aspect
//增强类
@Component
@Aspect//生成代理对象
public class UserProxy {
//在方法执行前,增加了新的功能
public void before() {
System.out.println("before方法执行了......");
}
}
4.spring文件中开启生成代理对象
<?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:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
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
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--开启组件扫描-->
<context:component-scan base-package="com.alibaba.spring5.aopanno"></context:component-scan>
<!--开启Aspect生成代理对象:如果类上有Aspect注解,就生成代理对象-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
5.配置不同类型的通知
//增强类
@Component
@Aspect//生成代理对象
public class UserProxy {
//在方法执行前,增加了新的功能
@Before(value = "execution( * com.alibaba.spring5.aopanno.User.method(..))")
public void before() {
System.out.println("before方法执行了......");
}
//最后输出
@AfterThrowing(value = "execution( * com.alibaba.spring5.aopanno.User.method(..))")
public void afterThrowing() {
System.out.println("AfterThrowing方法执行了......");
}
//倒数第二输出,如果发生异常,则不输出
@AfterReturning(value = "execution( * com.alibaba.spring5.aopanno.User.method(..))")
public void afterReturning() {
System.out.println("AfterReturning方法执行了......");
}
//倒数第三输出
@After(value = "execution( * com.alibaba.spring5.aopanno.User.method(..))")
public void after() {
System.out.println("After方法执行了......");
}
//环绕通知:在方法的最开始以及方法的最后(最后一个)
@Around(value = "execution( * com.alibaba.spring5.aopanno.User.method(..))")
public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("Around方法执行了......");
proceedingJoinPoint.proceed();//执行被增强的类方法
System.out.println("Around方法执行了......");
}
}
测试结果
@Test
public void testMethod(){
//1.读取配置文件
ApplicationContext bean = new ClassPathXmlApplicationContext("bean1.xml");
//2.获取创建好的对象
User user = bean.getBean("user", User.class);
//3.调用方法测试结果
user.method();
}
提取切入点表达式,作为公共的使用
//增强类
@Component
@Aspect//生成代理对象
public class UserProxy {
//提取切入点表达式
@Pointcut(value = "execution(* com.alibaba.spring5.aopanno.User.method(..))")
public void common(){}
//在方法执行前,增加了新的功能
@Before(value = "common()")
public void before() {
System.out.println("before方法执行了......");
}
//在被增强的方法之后,有异常才输出
@AfterThrowing(value = "common()")
public void afterThrowing() {
System.out.println("AfterThrowing方法执行了......");
}
//在被增强的方法之后,如果发生异常,则不输出
@AfterReturning(value = "common()")
public void afterReturning() {
System.out.println("AfterReturning方法执行了......");
}
//在有无异常之后,最后环绕之前,如果有异常,最后环绕则不输出
@After(value = "common()")
public void after() {
System.out.println("After方法执行了......");
}
//环绕通知:在最开头输出一次,最结尾输出一次,如果有异常,最后一次则不输出
@Around(value = "common()")
public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("Around方法执行了......");
proceedingJoinPoint.proceed();//执行被增强的类方法
System.out.println("Around方法执行了......");
}
}
有多个增强类对同一个方法进行增加新的功能,设置增强类的优先级:
使用@Order注解设置优先级,数字越小,优先级越高
//增强类
@Component
@Aspect//生成代理对象
@Order(1314)
public class PersonProxy {
//提取切入点表达式
@Pointcut(value = "execution(* com.alibaba.spring5.aopanno.User.method(..))")
public void common(){}
//在方法执行前,增加了新的功能
@Before(value = "common()")
public void before() {
System.out.println("PersonProxy ==> before方法执行了......");
}
}
完全注解开发
创建配置类,不需要xml配置文件
@Configuration//表示这是一个配置类
@ComponentScan(basePackages = "com.alibaba.spring5")//表示扫描该包下所有对象
@EnableAspectJAutoProxy(proxyTargetClass = true)//扫描代理对象注解
public class SpringConfig {
}
------------------------------------------------------
基于配置文件完成AOP
创建被增强类和增强类
//被增强类
public class Student {
//被增强方法
public void method(){
System.out.println("被增强方法执行了......");
}
}
------------------------------------------------
//增强类
public class StudentProxy {
//增强方法
public void method(){
System.out.println("增强方法执行了......");
}
}
配置spring config文件
<?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:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
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
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--配置需要创建的对象-->
<bean id="student" class="com.alibaba.spring5.aopxml.Student"></bean>
<bean id="studentProxy" class="com.alibaba.spring5.aopxml.StudentProxy"></bean>
<!--配置aop增强-->
<aop:config>
<!--切入点-->
<aop:pointcut id="p" expression="execution(* com.alibaba.spring5.aopxml.Student.method(..))"/>
<!--配置切面-->
<aop:aspect ref="studentProxy">
<!--增强新的功能-->
<aop:before method="method" pointcut-ref="p"></aop:before>
</aop:aspect>
</aop:config>
</beans>
测试结果
@Test
public void testMethod(){
//1.读取配置文件
ApplicationContext bean = new ClassPathXmlApplicationContext("bean1.xml");
//2.获取创建好的对象
Student student = bean.getBean("student", Student.class);
//3.调用方法测试结果
student.method();
}