一.Spring概述
Spring 是轻量级的开源的 JavaEE 框架,Spring为简化企业级开发而生,使用Spring开发可以将Bean对象,Dao组件对象,Service组件对象等交给Spring容器来管理,这样使得很多复杂的代码在Spring中开发却变得非常的优雅和简洁,有效的降低代码的耦合度,极大的方便项目的后期维护、升级和扩展。
Spring 有两个核心部分:IOC 和 Aop
(1)IOC:控制反转,指的是将对象的创建权交给Spring去创建,使用Spring之前,对象的创建都是由我们自己在代码中new创建。而使用Spring之后。对象的创建都是由给了Spring框架。
(2)Aop:面向切面,不修改源代码进行功能增强。
Spring快速入门
-
导入Spring 坐标
<dependencies> <dependency> <groupId>org.springframework</groupId>` <artifactId>spring-context</artifactId> <version>${spring.version}</version>` </dependency> </dependencies>
-
创建Bean
public interface UserDao { public void save(); }
public class UserDaoImpl implements UserDao { @Override public void save() { System.out.println("UserDao Startinng...."); } }
-
创建Spring核心配置文件 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.terence.dao.impl.UserDaoImpl"></bean> </beans>
-
创建ApplicationContext对象,通过getBean方法获得Bean实例
public class UserDaoDemo { public static void main(String[] args) { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); UserDao userDao = (UserDao) applicationContext.getBean("userDao"); userDao.save(); } }
二. IOC
1. IOC操作Bean管理
1、基于 xml方式创建对象
(1)在 spring 配置文件中,使用 bean 标签,标签里面添加对应属性,就可以实现对象创建
(2)在 bean 标签有很多属性,介绍常用的属性
id 属性:唯一标识
class 属性:类全路径(包类路径)
(3)创建对象时候,默认也是执行无参数构造方法完成对象创建
2、基于 xml方式注入属性
DI:依赖注入,就是注入属性
3、第一种注入方式:使用 set 方法进行注入
(1)创建类,定义属性和对应的 set 方法
public class User {
//创建属性
private String Name;
private String Age;
//创建属性对应的 set 方法
public void setName(String Name) {
this.Name = Name;
}
public void setAge(String Age) {
this.Age = Age;
}
}
(2)在 spring 配置文件配置对象创建,配置属性注入
<bean id="User" class="com.yaoqi.bean.User">
<!--使用 property 完成属性注入
name:类里面属性名称
value:向属性注入的值
-->
<property name="Name" value="张三"></property>
<property name="Age" value="1"></property>
</bean>
4、第二种注入方式:使用有参数构造进行注入
(1)创建类,定义属性,创建属性对应有参数构造方法
/使用有参数构造注入/使用有参数构造注入/
public class User {
//属性
private String name;
private String age;
//有参数构造
public User(String name,String age) {
this.name = name;
this.age = age;
}
}
(2)在 spring 配置文件中进行配置
<!--3 有参数构造注入属性-->
<bean id="User" class="com.yaoqi.bean.User">
<constructor-arg name="name" value="张三"></constructor-arg>
<constructor-arg name="age" value="18"></constructor-arg>
</bean>
2. 注入其他类型属性
1、字面量
(1)null 值
<property name="属性名">
<null/>
</property>
(2)属性值包含特殊符号
-
把<>进行转义 < >
-
把带特殊符号内容写到 CDATA
<property name="属性名">
<!--设置值为<<深圳>>-->
<value><![CDATA[<<深圳>>]]></value>
</property>
2、注入属性-外部 bean
(1)创建两个类 service 类和 dao 类
(2)在 service 调用 dao 里面的方法
(3)在 spring 配置文件中进行配置
public class UserService {
//创建 UserDao 类型属性,生成 set 方法
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void add() {
System.out.println("service add...............");
userDao.update();
}
}
<bean id="userService" class="com.yaoqi.service.UserService">
<property name="userDao" ref="userDaoImpl"></property>
</bean>
<bean id="userDaoImpl" class="com.yaoqi.dao.UserDaoImpl"></bean>
3、注入属性-内部 bean
(1)一对多关系:部门和员工
(2)在实体类之间表示一对多关系,员工表示所属部门,使用对象类型属性进行表示
//部门类
public class Dept {
private String dname;
public void setDname(String dname) {
this.dname = dname;
}
}
//员工类
public class Emp {
private String ename;
private String gender;
private Dept dept;
public void setDept(Dept dept) {
this.dept = dept;
}
public void setEname(String ename) {
this.ename = ename;
}
public void setGender(String gender) {
this.gender = gender;
}
}
(3)在 spring 配置文件中进行配置
<bean id="emp" class="com.yaoqi.bean.Emp">
<!--设置两个普通属性-->
<property name="ename" value="张三"></property>
<property name="gender" value="男"></property>
<!--设置对象类型属性-->
<property name="dept">
<bean id="dept" class="com.yaoqi.bean.Dept">
<property name="dname" value="销售部"></property>
</bean>
</property>
</bean>
4、注入属性-级联赋值
(1)第一种写法
<bean id="emp" class="com.yaoqi.bean.Emp">
<!--设置两个普通属性-->
<property name="ename" value="张三"></property>
<property name="gender" value="男"></property>
<!--级联赋值-->
<property name="dept" ref="dept"></property>
</bean>
<bean id="dept" class="com.yaoqi.bean.Dept">
<property name="dname" value="销售部"></property>
</bean>
(2)第二种写法
<bean id="emp" class="com.yaoqi.bean.Emp">
<!--设置两个普通属性-->
<property name="ename" value="张三"></property>
<property name="gender" value="男"></property>
<!--级联赋值-->
<property name="dept.dname" value="销售部"></property>
</bean>
3. 注入集合属性
1、注入数组类型属性
2、注入 List 集合类型属性
3、注入 Map 集合类型属性
(1)创建类,定义数组、list、map、set 类型属性,生成对应 set 方法
public class Stu {
//1 数组类型属性
private String[] courses;
//2 list 集合类型属性
private List<String> list;
//3 map 集合类型属性
private Map<String,String> maps;
//4 set 集合类型属性
private Set<String> sets;
public void setSets(Set<String> sets) {
this.sets = sets;
}
public void setCourses(String[] courses) {
this.courses = courses;
}
public void setList(List<String> list) {
this.list = list;
}
public void setMaps(Map<String, String> maps) {
this.maps = maps;
}
}
(2)在 spring 配置文件进行配置
<bean id="stu" class="com.yaoqi.bean.Stu">
<!--数组类型属性注入-->
<property name="courses">
<array>
<value>A</value>
<value>B</value>
</array>
</property>
<!--list 类型属性注入-->
<property name="list">
<list>
<value>A</value>
<value>B</value>
</list>
</property>
<!--map 类型属性注入-->
<property name="maps">
<map>
<entry key="A" value="a"></entry>
<entry key="B" value="b"></entry>
</map>
</property>
<!--set 类型属性注入-->
<property name="sets">
<set>
<value>A</value>
<value>B</value>
</set>
</property>
</bean>
4、在集合里面设置对象类型值
<!--创建多个class对象-->
<bean id="class1" class="com.yaoqi.bean.Class">
<property name="cname" value="语文"></property>
</bean>
<bean id="class2" class="com.yaoqi.bean.Class">
<property name="cname" value="数学"></property>
</bean>
<!--注入 list 集合类型,值是对象-->
<property name="classList">
<list>
<ref bean="class1"></ref>
<ref bean="class2"></ref>
</list>
</property>
4. 工厂Bean(FactoryBean)
1、Spring 有两种类型 bean,一种普通 bean,另外一种工厂 bean(FactoryBean)
2、普通 bean:在配置文件中定义 bean 类型就是返回类型
3、工厂 bean:在配置文件定义 bean 类型可以和返回类型不一样
第一步 创建类,让这个类作为工厂 bean,实现接口 FactoryBean
第二步 实现接口里面的方法,在实现的方法中定义返回的 bean 类型
public class MyBean implements FactoryBean<Class> {
//定义返回 bean
@Override
public Course getObject() throws Exception {
Course course = new Course();
course.setCname("英语");
return course;
}
@Override
public Class<?> getObjectType() {
return null;
}
@Override
public boolean isSingleton() {
return false;
}
}
<bean id="myBean" class="com.yaoqi.factorybean.MyBean">
</bean>
@Test
public void test3() {
ApplicationContext context = new ClassPathXmlApplicationContext("bean3.xml");
Course course = context.getBean("myBean", Course.class);
System.out.println(course);
}
5. Bean作用域
scope:指对象的作用范围,取值如下:
取值范围 | 说明 |
---|---|
singleton | 默认值,单例的 |
prototype | 多例的 |
request | WEB 项目中,Spring 创建一个 Bean 的对象,将对象存入到 request 域中 |
session | WEB 项目中,Spring 创建一个 Bean 的对象,将对象存入到 session 域中 |
global session | WEB 项目中,应用在 Portlet 环境,如果没有 Portlet 环境那么globalSession 相当于 session |
6. Bean 生命周期
-
执行无参数构造创建Bean实例
-
调用set方法设置属性值
—初始之前执行的方法
-
执行初始化的方法
—初始之后执行的方法
-
获取创建Bean实例对象
-
执行销毁的方法
(1)创建类,实现接口 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;
}
}
<!--配置后置处理器-->
<bean id="myBeanPost" class="com.yaoqi.bean.MyBeanPost"></bean>
7. 外部属性文件
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-60WWDvFb-1658717351881)(C:\Users\KONGP\Desktop\总笔记\01-Spring\image-20220628173255831.png)]
把外部 properties 属性文件引入到 spring 配置文件中引入 context 名称空间
<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"
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/util
http://www.springframework.org/schema/util/spring-util.xsd
<!--context空间名称-->
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="driverClassName" value="${prop.driverClass}"></property>
<property name="url" value="${prop.url}"></property>
<property name="username" value="${prop.userName}"></property>
<property name="password" value="${prop.password}"></property>
</bean>
三.Spring常用注解
@Component 使用在类上用于实例化Bean
@Controller 使用在web层类上用于实例化Bean
@Service 使用在service层类上用于实例化Bean
@Repository 使用在dao层类上用于实例化Bean
@Autowired 使用在字段上用于根据类型依赖注入
@Qualifier 结合@Autowired一起使用用于根据名称进行依赖注入
@Resource 相当于@Autowired+@Qualifier,按照名称进行注入
@Value 注入普通属性
@Scope 标注Bean的作用范围
@Configuration 用于指定当前类是一个 Spring 配置类,当创建容器时会从该类上加载注解
@Bean 使用在方法上,标注将该方法的返回值存储到 Spring 容器中
@PropertySource 用于加载.properties 文件中的配置
@Import 用于导入其他配置类
使用注解进行开发时,需要在applicationContext.xml中配置组件扫描,作用是指定哪个包及其子包下的Bean需要进行扫描以便识别使用注解配置的类、字段和方法,或者使用@ComponentScan注解,用于指定 Spring 在初始化容器时要扫描的包。
<!--注解的组件扫描-->
<context:component-scan base-package="com.yaoqi"></context:component-scan>
四.AOP
1. AOP 的作用及其优势
作用:在程序运行期间,在不修改源码的情况下对方法进行功能增强
优势:减少重复代码,提高开发效率,并且便于维护
2. AOP 的底层实现
实际上,AOP 的底层是通过 Spring 提供的的动态代理技术实现的。在运行期间,Spring通过动态代理技术动态的生成代理对象,代理对象方法执行时进行增强功能的介入,在去调用目标对象的方法,从而完成功能的增强。
3. AOP 的动态代理技术
第一种 有接口情况,使用 JDK 动态代理(创建接口实现类代理对象,增强类的方法)
第二种 没有接口情况,使用 CGLIB 动态代理(创建子类的代理对象,增强类的方法)
(1)创建接口,定义方法
public interface UserDao {
public int add(int a,int b);
}
(2)创建接口实现类,实现方法
public class UserDaoImpl implements UserDao {
@Override
public int add(int a, int b) {
return a+b;
}
}
(3)使用 Proxy 类创建接口代理对象
public class JDKProxy {
public static void main(String[] args) {
//创建接口实现类代理对象
Class[] interfaces = {UserDao.class};
UserDaoImpl userDao = new UserDaoImpl();
UserDao dao = (UserDao)Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new UserDaoProxy(userDao));
int result = dao.add(1, 2);
System.out.println("result:"+result);
}
}
//创建代理对象代码
class UserDaoProxy implements InvocationHandler {
//1 把创建的是谁的代理对象,把谁传递过来
//有参数构造传递
private Object obj;
public UserDaoProxy(Object obj) {
this.obj = obj;
}
//增强的逻辑
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("方法之前执行....");
//被增强的方法执行
Object result = method.invoke(obj, args);
System.out.println("方法之后执行....");
return result;
}
}
4. AOP 的相关术语
常用的术语如下:
Target(目标对象):代理的目标对象
Proxy (代理):一个类被 AOP 织入增强后,就产生一个结果代理类
Joinpoint(连接点):所谓连接点是指那些被拦截到的点。在spring中,这些点指的是方法,因为spring只支持方法类型的连接点
Pointcut(切入点):所谓切入点是指我们要对哪些 Joinpoint 进行拦截的定义
Advice(通知/ 增强):所谓通知是指拦截到 Joinpoint 之后所要做的事情就是通知
Aspect(切面):是切入点和通知(引介)的结合
Weaving(织入):是指把增强应用到目标对象来创建新的代理对象的过程。spring采用动态代理织入,而AspectJ采用编译期织入和类装载期织入
5. AOP 操作(AspectJ 注解)
1、创建类,在类里面定义方法
public class User {
public void add() {
System.out.println("add starting...");
}
}
2、创建增强类(编写增强逻辑)
(1)在增强类里面,创建方法,让不同方法代表不同通知类型
//增强的类
public class UserProxy {
public void before() {
System.out.println("before starting...");
}
}
3、进行通知的配置
(1)在 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.yaoqi.package"></context:component-scan>
(2)使用注解创建 User 和 UserProxy 对象
(3)在增强类上面添加注解 @Aspect
//增强的类
@Component
@Aspect //生成代理对象
public class UserProxy {
(4)在 spring 配置文件中开启生成代理对象
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
4、配置不同类型的通知
(1)在增强类的里面,在作为通知方法上面添加通知类型注解,使用切入点表达式配置
@Component
@Aspect
public class UserProxy {
//前置通知
@Before(value = "execution(*com.yaoqi.package.User.add(..))")
public void before() {
System.out.println("before.........");
}
//后置通知
@AfterReturning(value = "execution(*com.yaoqi.package.User.add(..))")
public void afterReturning() {
System.out.println("afterReturning.........");
}
//最终通知
@After(value = "execution(*com.yaoqi.package.User.add(..))")
public void after() {
System.out.println("after.........");
}
//异常通知
@AfterThrowing(value = "execution(*com.yaoqi.package.User.add(..))")
public void afterThrowing() {
System.out.println("afterThrowing.........");
}
//环绕通知
@Around(value = "execution(*com.yaoqi.package.User.add(..))")
public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("环绕之前.........");
//被增强的方法执行
proceedingJoinPoint.proceed();
System.out.println("环绕之后.........");
}
}
5、相同的切入点抽取
//相同切入点抽取
@Pointcut(value = "execution(*com.yaoqi.package.User.add(..))")
public void commondemo() {
}
//前置通知
@Before(value = "commondemo()")
public void before() {
System.out.println("before.........");
}
6. AOP 操作(AspectJ 配置文件)
1、创建两个类,增强类和被增强类,创建方法
2、在 spring 配置文件中创建两个类对象
<bean id="book" class="com.yaoqi.Book"></bean>
<bean id="bookProxy" class="com.yaoqi.BookProxy"></bean>
3、在 spring 配置文件中配置切入点
<!--配置 aop 增强-->
<aop:config>
<!--切入点-->
<aop:pointcut id="p" expression="execution(*com.yaoqi..Book.buy(..))"/>
<!--配置切面-->
<aop:aspect ref="bookProxy">
<!--增强作用在具体的方法上-->
<aop:before method="before" pointcut-ref="p"/>
</aop:aspect>
</aop:config>
5、相同的切入点抽取
//相同切入点抽取
@Pointcut(value = "execution(*com.yaoqi.package.User.add(..))")
public void commondemo() {
}
//前置通知
@Before(value = "commondemo()")
public void before() {
System.out.println("before.........");
}
7. AOP 操作(AspectJ 配置文件)
1、创建两个类,增强类和被增强类,创建方法
2、在 spring 配置文件中创建两个类对象
<bean id="book" class="com.yaoqi.Book"></bean>
<bean id="bookProxy" class="com.yaoqi.BookProxy"></bean>
3、在 spring 配置文件中配置切入点
<!--配置 aop 增强-->
<aop:config>
<!--切入点-->
<aop:pointcut id="p" expression="execution(*com.yaoqi..Book.buy(..))"/>
<!--配置切面-->
<aop:aspect ref="bookProxy">
<!--增强作用在具体的方法上-->
<aop:before method="before" pointcut-ref="p"/>
</aop:aspect>
</aop:config>