目录
二、IoC(Inversion of Control )控制反转
三、DI(Dependency Injection)依赖注入
3.2、spring-context.xml引入AOP命名空间
一、Spring环境搭建
1. pom.xml中引入Spring常用依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.qf</groupId>
<artifactId>day0327</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.6.RELEASE</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.27</version>
</dependency>
</dependencies>
</project>
2. 创建Spring配置文件
一定要先导入依赖
命名无限制,约定俗成命名有:spring-context.xml、applicationContext.xml、beans.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">
</beans>
二、IoC(Inversion of Control )控制反转
Inverse Of Controll:控制反转
反转了依赖关系的满足方式,由之前的自己创建依赖对象,变为由工厂推送。(变主动为被动,即反转)
解决了具有依赖关系的组件之间的强耦合,使得项目形态更加稳健
1、项目中强耦合问题
public class UserDAOImpl implements UserDAO{....}
public class UserServiceImpl implements UserService {
// !!!强耦合了UserDAOImpl!!!,使得UserServiceImpl变得不稳健!!
private UserDAO userDAO= new UserDAOImpl();
@Override
public User queryUser() {
return userDAO.queryUser();
}
....
}
2、解决方案
// 不引用任何一个具体的组件(实现类),在需要其他组件的位置预留存取值入口(set/get)
public class UserServiceImpl implements UserService {
// !!!不再耦合任何DAO实现!!!,消除不稳健因素!!
private UserDAO userDAO;
// 为userDAO定义set/get,允许userDAO属性接收spring赋值
//Getters And Setters
@Override
public User queryUser() {
return userDAO.queryUser();
}
....
}
<bean id="userDAO" class="com.qf.spring.part1.injection.UserDaoImpl"></bean>
<!-- UserServiceImpl组件 -->
<bean id="userService" class="com.qf.spring.part1.injection.UserServiceImpl">
<!-- 由spring为userDAO属性赋值,值为id="userDAO"的bean -->
<property name="userDAO" ref="userDAO"/>
</bean>
此时,如果需要更换其他UserDAO实现类,则UserServiceImpl不用任何改动!
则此时的UserServiceImpl组件变得更加稳健!
三、DI(Dependency Injection)依赖注入
1、概念
在Spring创建对象的同时,为其属性赋值,称之为依赖注入。
2、Set注入
创建对象时,Spring工厂会通过Set方法为对象的属性赋值。
2.1、定义目标Bean类型
public class User {
private Integer id;
private String password;
private String sex;
private Integer age;
private Date bornDate;
private String[] hobbys;
private Set<String> phones;
private List<String> names;
private Map<String,String> countries;
private Properties files;
//Getters And Setters
}
2.3、基本类型 + 字符串类型 + 日期类型
<bean id="u1" class="com.qf.spring.part1.injection.User">
<!--base field-->
<property name="id" value="1001" />
<property name="password" value="123456" />
<property name="sex" value="male" />
<property name="age" value="20" />
<property name="bornDate" value="1990/1/1" /><!--注意格式"/"-->
</bean>
2.4、容器类型
<bean id="u1" class="com.qf.spring.part1.injection.User">
<!--Array-->
<property name="hobbys">
<array>
<value>Run</value>
<value>Swim</value>
<value>Climb</value>
</array>
</property>
<!--Set-->
<property name="phones">
<set>
<value>13777777777</value>
<value>13888888888</value>
<value>13999999999</value>
</set>
</property>
<!--List-->
<property name="names">
<list>
<value>tom</value>
<value>jack</value>
<value>marry</value>
</list>
</property>
<!--Map-->
<property name="countries">
<map>
<entry key="CN" value="China" />
<entry key="US" value="America" />
<entry key="KR" value="Korea" />
</map>
</property>
<!--Properties-->
<property name="files">
<props>
<prop key="first">One</prop>
<prop key="second">Two</prop>
<prop key="third">Three</prop>
</props>
</property>
</bean>
2.5、自建类型
<!--次要bean,被作为属性-->
<bean id="userDao" class="com.qf.spring.part1.injection.UserDaoImpl" />
<!--主要bean,操作的主体-->
<bean id="userService" class="com.qf.spring.part1.injection.UserServiceImpl">
<property name="ud" ref="userDao" /><!--ud属性引用userDao对象-->
</bean>
3、 构造注入
在实体类中创建有参构造(有参构造也必须有)
<bean id="us" class="com.qf.entity.person">
<constructor-arg name="id" value="2"></constructor-arg>
<constructor-arg name="password" value="2"></constructor-arg>
<constructor-arg name="sex" value="3"/>
<constructor-arg name="age" value="4"/>
<constructor-arg name="bornDate" ref="date"/>
</bean>
4、自动注入
不用在配置中 指定为哪个属性赋值,及赋什么值.
由spring自动根据某个 "原则" ,在工厂中查找一个bean,为属性注入属性值
public class UserServiceImpl implements UserService {
private UserDAO userDAO;
//Getters And Setters
....
}
<bean id="userDao" class="com.qf.spring.part1.injection.UserDaoImpl" />
<!-- 为UserServiceImpl中的属性基于类型自动注入值 -->
<bean id="userService" class="com.qf.spring.part1.injection.UserServiceImpl" autowire="byType"></bean>
<bean id="userDao" class="com.qf.spring.part1.injection.UserDaoImpl" />
<!-- 为UserServiceImpl中的属性基于类型自动注入值 -->
<bean id="userService" class="com.qf.spring.part1.injection.UserServiceImpl" autowire="byName"></bean>
参数 :byType(一般用于只有一个 )
byName(用于一个或多个 且需要注入的属性名称除首字母小写其它得相同)
四、 注解开发
1、声明bean
用于替换自建类型组件的 <bean...>标签;可以更快速的声明bean
@Service 业务类专用
@Repository dao实现类专用
@Controller web层专用
@Component 通用(前四个作用都一样)
@Scope 用户控制bean的创建模式
// @Service说明 此类是一个业务类,需要将此类纳入工厂 等价替换掉 <bean class="xxx.UserServiceImpl">
// @Service默认beanId == 首字母小写的类名"userServiceImpl"
// @Service("userService") 自定义beanId为"userService"
@Service //声明bean,且id="userServiceImpl"
@Scope("singleton") //声明创建模式,默认为单例模式 ;@Scope("prototype")即可设置为多例模式
public class UserServiceImpl implements UserService {
...
}
2、注入(DI)
用于完成bean中属性值的注入
@Autowired 基于类型自动注入
@Resource 基于名称自动注入(Resource(name="xxxx"))
@Qualifier("userDAO") 限定要自动注入的bean的id,一般和@Autowired联用
@Value 注入简单类型数据 (jdk8种+String set注入)
@Service
public class UserServiceImpl implements UserService {
@Autowired //注入类型为UserDAO的bean
@Qualifier("userDAO2") //如果有多个类型为UserDAO的bean,可以用此注解从中挑选一个
private UserDAO userDAO;
}
@Service
public class UserServiceImpl implements UserService {
@Resource("userDAO3") //注入id=“userDAO3”的bean
private UserDAO userDAO;
/*
@Resource //注入id=“userDAO”的bean
private UserDAO userDAO;
*/
}
public class XX{
@Value("100") //注入数字
private Integer id;
@Value("shine") //注入String
private String name;
}
五、控·制简单对象的单例、多例模式
配置< bean scope="singleton | prototype" />
<!--
singleton(默认):每次调用工厂,得到的都是同一个对象。
prototype:每次调用工厂,都会创建新的对象。
-->
<bean id="mc" class="com.qf.zcg.spring.day1.t1.basic.MyClass" scope="singleton" />
六、面向切面编程(AOP)
1、概念
(在不改变源代码的基础上动态的实现部分功能 )
简单说就是那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块之间的耦合度,并有利于未来的可操作性和可维护性。
2、作用
Spring的AOP编程即是通过动态代理类为原始类的方法添加辅助功能。
3、环境搭建
3.1、引入AOP相关依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.1.6.RELEASE</version>
</dependency>
3.2、spring-context.xml引入AOP命名空间
4、开发流程
(一、第一种定义通知类)
定义原始类
前置通知:MethodBeforeAdvice
后置通知:AfterAdvice
后置通知:AfterReturningAdvice //有异常不执行,方法会因异常而结束,无返回值
异常通知:ThrowsAdvice
环绕通知:MethodInterceptor
package com.qf.aaron.aop.basic;
public interface UserService {
public void save();
}
-----------------------------
package com.qf.aaron.aop.basic;
public class UserServiceImpl implements UserService {
public void save() {
System.out.println("save method executed...");
}
}
定义通知类(添加额外功能)
package com.qf.aaron.aop.basic;
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
public class MyAdvice implements MethodBeforeAdvice { //实现前置通知接口
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println("before advice executed...");
}
}
定义bean标签
<!--原始对象-->
<bean id="us" class="com.qf.aaron.aop.basic.UserServiceImpl" />
<!--通知类 辅助对象-->
<bean id="myAdvice" class="com.qf.aaron.aop.basic.MyAdvice" />
定义切入点(PointCut)
形成切面(Aspect)
<aop:config>
<!--切点-->
<aop:pointcut id="myPointCut" expression="execution(* save())" />
<!--组装切面 -->
<aop:advisor advice-ref="myAdvice" pointcut-ref="myPointCut" />
</aop:config>
(二、第二种通过写Aspect类)
定义原始类
public interface UserService {
void add();
}
public class UserServiceImpl implements UserService {
@Override
public void add() {
System.out.println("添加了");
}
}
定义通知类(添加额外功能MyAspect)
public class MyAspect {
public void before(){
System.out.println("前置通知执行");
}
public void after(){
System.out.println("后置通知执行");
}
public void afterReturning(){
System.out.println("返回通知执行");
}
public void afterThrowing(){
System.out.println("异常通知执行");
}
public void around(ProceedingJoinPoint pjd){
System.out.println("环绕通知前置执行");
try {
pjd.proceed();
} catch (Throwable throwable) {
throwable.printStackTrace();
}
System.out.println("环绕通知后置执行");
}
}
定义bean标签
<bean id="userService" class="com.qianfeng.service.impl.UserServiceImpl" />
<bean id="myAspect" class="com.qianfeng.advice.MyAspect"/>
<!--配置切点-->
<aop:config>
<aop:pointcut id="myPointCut1" expression="execution(* com.qianfeng.service.UserService.add())"/>
<aop:pointcut id="myPointCut2" expression="execution(* com.qianfeng.service.UserService.delete())"/>
<aop:pointcut id="myPointCut3" expression="execution(* com.qianfeng.service.UserService.getAll())"/>
<aop:pointcut id="myPointCut4" expression="execution(* com.qianfeng.service.UserService.getOne())"/>
<aop:pointcut id="myPointCut5" expression="execution(* com.qianfeng.service.UserService.update())"/>
<!--advice-ref 配置通知-->
pointcut-ref 配置切点
<aop:aspect ref="myAspect">
<aop:before method="before" pointcut-ref="myPointCut1"/>
<aop:after method="after" pointcut-ref="myPointCut2"/>
<aop:after-returning method="afterReturning" pointcut-ref="myPointCut3"/>
<aop:after-throwing method="afterThrowing" pointcut-ref="myPointCut4"/>
<aop:around method="around" pointcut-ref="myPointCut5"/>
</aop:aspect>
</aop:config>
4.1、小结
通过AOP提供的编码流程,更便利的定制切面,更方便的定制了动态代理。
进而彻底解决了辅助功能冗余的问题;
业务类中职责单一性得到更好保障;
辅助功能也有很好的复用性。