文章目录
一 Spring在实际开发中的运用
1.1 什么是Spring
- 轻量级的DI/IOC与AOP的容器框架!
- 面试题:BeanFactory与ApplicationContext的区别?
答:ApplicationContext是BeanFactory的子类,它拥有更加强大的一些方法(邮件,国际化,…),BeanFactory创建的Bean默认是懒加载,ApplicationContext是BeanFactory的子类是迫切加载!!!
1.2 导包
Spring需要的包
<!--Spring的核心包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.2.5.RELEASE</version>
</dependency>
<!--Context包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.2.5.RELEASE</version>
</dependency>
<!--aop的包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.2.5.RELEASE</version>
</dependency>
<!--切面的一个包(织入)-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.8</version>
</dependency>
<!-- Spring的测试包 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>4.2.5.RELEASE</version>
<!--scope:范围,只能在test包中使用-->
<scope>test</scope>
</dependency>
<!--junit的测试支持-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
引入一些插件与资源
- 需要去读到java中的xml文件(默认不会编译)
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
<resource>
<directory>src/test/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
</resources>
</build>
二 构造器注入
- 标签:
constructor-arg
- 属性 index/name/type = 下标/名称/类型
- 属性 value/ref = 普通的值/引用
2.1 根据下标进行引入
<bean id="myBean" class="wltyx.nyybw._02_constructor.MyBean">
<constructor-arg index="0" value="小莫" />
<constructor-arg index="1" value="99" />
</bean>
2.2 根据名称进行引入
<bean id="myBean" class="wltyx.nyybw._02_constructor.MyBean">
<constructor-arg name="name" value="小莫" />
<constructor-arg name="age" value="99" />
</bean>
2.3 根据类型进行引入
不能出现重复类型
<bean id="myBean" class="wltyx.nyybw._02_constructor.MyBean">
<constructor-arg type="java.lang.String" value="小莫" />
<constructor-arg type="java.lang.Integer" value="99" />
</bean>
2.4 自动进行引入
顺序是不允许修改的
<bean id="myBean" class="wltyx.nyybw._02_constructor.MyBean">
<constructor-arg value="小莫" />
<constructor-arg value="99" />
</bean>
2.5 在其它的bean的方式
外部bean是可以重复使用
<bean id="otherBean" class="wltyx.nyybw._02_constructor.OtherBean">
</bean>
<bean id="myBean" class="wltyx.nyybw._02_constructor.MyBean">
<!-- 外部bean -->
<constructor-arg index=0 ref="otherBean" />
<!-- 内部bean -->
<constructor-arg index="2">
<bean class="wltyx.nyybw._02_constructor.OtherBean" />
</constructor-arg>
</bean>
三 属性注入
3.1 普通属性
准备属性
// 简单属性
private Long id;
private String name;
private Boolean sex;
private BigDecimal salary;
配置的代码
<property name="id" value="1" />
<property name="name" value="王霸天" />
<property name="sex" value="true"/>
<property name="salary" value="58" />
3.2 集合
准备的属性
- list与set(不允许重复)
- 关键的那个标签(list,set,array)写错也可以用(但是不建议)
private List<String> list;
private Set<String> set;
private List<OtherBean> otherBeanList;
private Set<OtherBean> otherBeanSet;
配置的代码
<property name="list">
<list>
<value>abc</value>
<value>abc</value>
<value>123</value>
<value>321</value>
</list>
</property>
<!--Set<String> set :无序,不重复-->
<property name="set">
<set>
<value>abc</value>
<value>abc</value>
<value>123</value>
<value>321</value>
</set>
</property>
<!--List<OtherBean> otherBeanList-->
<property name="otherBeanList">
<list>
<ref bean="otherBean" />
<ref bean="otherBean" />
<bean class="wltyx.nyybw._03_di.OtherBean" />
<bean class="wltyx.nyybw._03_di.OtherBean" />
</list>
</property>
<!--Set<OtherBean> otherBeanSet-->
<property name="otherBeanSet">
<set>
<ref bean="otherBean" />
<ref bean="otherBean" />
<bean class="wltyx.nyybw._03_di.OtherBean" />
<bean class="wltyx.nyybw._03_di.OtherBean" />
</set>
</property>
3.3 数组与properties
- 数组与properties都有两种写法(简写形式)
- properties的简写形式不支持中文
数组与properties
private String[] arrays;
private Properties props1;
private Properties props2;
xml配置
<!--String[] arrays :标准写法 -->
<!--
<property name="arrays">
<array>
<value>abc</value>
<value>def</value>
<value>gf</value>
</array>
</property>
-->
<!--String[] arrays :简写形式 (数组中每个值用,隔开)-->
<property name="arrays" value="abc,dfe,fd" />
<!--Properties props1:标准写法-->
<property name="props1">
<props>
<prop key="driver">com.mysql.jdbc.Driver</prop>
<prop key="url">jdbc:mysql:///spring哈哈</prop>
<prop key="username">root</prop>
<prop key="password">admin</prop>
</props>
</property>
<!--Properties props2:简写形式(不支持中文)-->
<property name="props2">
<value>
driver=com.mysql.jdbc.Driver
url=jdbc:mysql:///spring哈哈
username=root
</value>
</property>
四 XML的自动注入(了解即可)
- 自动注入有两种方式 (类型与名称)
- 设置全局的自动注入
<beans ... default-autowire="byType/byName">
- 单独为某一个bean配置自动注入
<bean ... autowire="byType/byName">
五 全注解(重要)
5.1 扫描相应的包
- 注意:引入context的头
<context:component-scan base-package="wltyx.nyybw._05_anno" />
5.2 在相应的类上加注解
-
Controller:控制层
-
Service:业务层
-
Repository:持久层
-
Component:组件(一个bean不知道在哪一层用这个)
-
@Autowired:注入功能
5.3 如果出现多个bean类型一样怎么办?
- 注解的bean有默认名称(类名【首字母小写】) 如
userDaoImpl
- 修改bean的名称
Component/Service/Repository/Controller("名称")
- 在注入bean的时候加上一个限定注解
@Autowired
@Qualifier("userJPADaoImpl")
//@Resource(name = "userJDBCDao")
private IUserDao userDao;
六 代理模式(了解即可)
- 分为静态与动态
- Spring使用的是动态代码:JDK(接口)/CGLIB
- 动态代理的代码
//通过JDK的方案创建一个动态代理对象呢?
/**
* java.lang.reflect:Proxy(代理)对象
* Foo Bar:张三,李四,王五
* ClassLoader loader :类加载器(随便给它一个)
Class<?>[] interfaces:接口(为什么这里是一个数组)
InvocationHandler h :增强功能(自己实现)
*/
IEmployeeService proxy = (IEmployeeService)Proxy.newProxyInstance(
this.getClass().getClassLoader(),
employeeService.getClass().getInterfaces(),
new InvocationHandler() {
/**
* @param proxy :代理对象(没有用)
* @param method :执行的方法
* @param args :方法中的参数
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = null;
try {
txManager.begin();
//在这里面完成功能增强
//通过反射执行相应的方法
result = method.invoke(employeeService, args);
txManager.commit();
} catch (Exception e) {
txManager.rollback();
e.printStackTrace();
} finally {
txManager.close();
}
return result;
}
});
七 Spring的AOP
7.1 XML版本
准备接口:IEmployeeService
public interface IEmployeeService {
void save();
void update();
void delete();
}
准备实现 EmployeeServiceImpl
public class EmployeeServiceImpl implements IEmployeeService {
@Override
public void save() {
System.out.println("送花给你....");
}
@Override
public void update() {
System.out.println("EmployeeServiceImpl udpate..");
}
@Override
public void delete() {
System.out.println("EmployeeServiceImpl delete..");
//int i = 1/0;
}
}
事务管理器(假)
public class TxManager {
public void begin(){
System.out.println("开启事务...");
}
public void commit(){
System.out.println("提交事务...");
}
public void rollback(Throwable e){
System.out.println("回滚事务...,错误的原因:"+e.getMessage());
}
public void close(){
System.out.println("关闭资源...");
}
//搞了一个ProceedingJoinPoint(连接点对象)
public void around(ProceedingJoinPoint joinPoint){
System.out.println(joinPoint.getArgs()); //参数
System.out.println(joinPoint.getSignature()); //方法签名(这个方法的所有信息)
System.out.println(joinPoint.getTarget().getClass()); //真实主题角色
System.out.println(joinPoint.getThis().getClass()); //代理主题角色
try {
begin();
joinPoint.proceed(); //执行对应的方法
commit();
} catch (Throwable e) {
rollback(e);
e.printStackTrace();
} finally {
close();
}
}
}
配置(关键)
- 引入aop的头
- 准备两个bean(EmployeeServiceImpl,TxManager)
- 如果有环绕通知,其它通知就不需要了
- 注意:何时,何地,做什么
<?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: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
">
<!--真实主题角色-->
<bean id="employeeService" class="wltyx.nyybw._08_xmlaop.EmployeeServiceImpl" />
<!--准备一个事务-->
<bean id="txManager" class="wltyx.nyybw._08_xmlaop.TxManager" />
<!--何时,何地,做什么事-->
<!--代表要做一个AOP的配置-->
<aop:config>
<!--
配置(定义)切点 在哪些类的哪些方法进行功能
id:切点名称(随便取)
expression:表达式(最后定位都是方法)
*:所有返回值
wltyx.nyybw._08_xmlaop:对应的包
I*Service:以I开头,Service结尾的所有接口(所有实现接口的方法)
*:所有方法
(..):所有参数
-->
<aop:pointcut id="pointcut" expression="execution(* wltyx.nyybw._08_xmlaop.I*Service.*(..))" />
<!--
切面:由切点和增强组成
ref="txManager" -> 对应的增强类
-->
<aop:aspect ref="txManager">
<!--
aop:before:前置通知
何地:在哪些类的哪些方法中:pointcut
何时:在方法执行之前:before
做什么事:执行txManager这个bean中的begin方法
try {
//前置通知
result = method.invoke(employeeService, args);
//后置通知
} catch (Exception e) {
//异常通知
} finally {
//最终通知
}
-->
<!--<aop:before method="begin" pointcut-ref="pointcut" />-->
<!--后置通知-->
<!--<aop:after-returning method="commit" pointcut-ref="pointcut" />-->
<!--异常通知 throwing这个错,方法中才可以获到(名字必需一致) -->
<!--<aop:after-throwing method="rollback" pointcut-ref="pointcut" throwing="e" />-->
<!--最终通知 -->
<!--<aop:after method="close" pointcut-ref="pointcut" />-->
<!--环绕通知-->
<aop:around method="around" pointcut-ref="pointcut" />
</aop:aspect>
</aop:config>
</beans>
测试
- 查看一下这个对象是否已经被代理
- 声明必需是接口
- 测试一下有异常与没有异常的区别
7.2 注解版
- 需要在相应的bean上加注解
- 配置包的扫描
- 所有的配置都是在TxManager加注解
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"
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="wltyx.nyybw._09_annoaop" />
<!--支持切面的注解-->
<aop:aspectj-autoproxy />
</beans>
TxManager
- 切点的名字是方法名()
package wltyx.nyybw._09_annoaop;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
/**
* @Aspect -> <aop:aspect ref="txManager">
*/
@Component
@Aspect
public class TxManager {
/**
* 切点:
* <aop:pointcut id="pointcut()" expression="execution(* wltyx.nyybw._09_annoaop.I*Service.*(..))" />
*/
@Pointcut("execution(* wltyx.nyybw._09_annoaop.I*Service.*(..))")
public void pointcut(){}
// @Before("pointcut()")
public void begin(){
System.out.println("开启事务...");
}
// @AfterReturning("pointcut()")
public void commit(){
System.out.println("提交事务...");
}
// @AfterThrowing(pointcut = "pointcut()",throwing = "e")
public void rollback(Throwable e){
System.out.println("回滚事务...,错误的原因:"+e.getMessage());
}
// @After("pointcut()")
public void close(){
System.out.println("关闭资源...");
}
//搞了一个ProceedingJoinPoint(连接点对象)
@Around("pointcut()")
public void around(ProceedingJoinPoint joinPoint){
System.out.println(joinPoint.getArgs()); //参数
System.out.println(joinPoint.getSignature()); //方法签名(这个方法的所有信息)
System.out.println(joinPoint.getTarget().getClass()); //真实主题角色
System.out.println(joinPoint.getThis().getClass()); //代理主题角色
try {
begin();
joinPoint.proceed(); //执行对应的方法
commit();
} catch (Throwable e) {
rollback(e);
e.printStackTrace();
} finally {
close();
}
}
}