(一)导入配置Spring的jar包
创建一个maven项目,在pom.xml中配置spring 需要的jar包
<?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>cn.lzj.</groupId>
<artifactId>Spring</artifactId>
<version>1.0-SNAPSHOT</version>
<!--
配置spring的需要的jar包
-->
<dependencies>
<!-- 配置spring的核心包 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.2.5.RELEASE</version>
</dependency>
<!-- 配置spring的上下文支持包 -->
<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>
<!-- 配合spring的测试包 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>4.2.5.RELEASE</version>
</dependency>
<!-- 配置切面包 -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.8</version>
</dependency>
<!--
需要去读到java中的xml文件(默认不会编译)
-->
<!-- 配置Juit测试包 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
<build>
<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>
<!-- 配置JDK1.8 -->
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
因为使用的是maven自动管理项目,所以在配置xml文件之后,idea可以自动导入jar包
(二) Spring构造器注入
(1) Spring的测试类准备
Spring测试复习:
1. 注入Spring测试的
2. 配置上下文的路径注解
三种方式:
1) 配置文件在classpath路径下
@ContextConfiguration(“classpath:SpringTest-Context.xml”)
2)配置文件在测试类的路径下
@ContextConfiguration(“classpath:cn/lzj/_01_contructor/SpringTest-Context.xml”)
3)配置文件的名为:测试类名-Context.xml
@ContextConfiguration
(2) Spring的注入构造器
标签: constructor-arg
属性: index/name/type = 下标/名称/类型
属性: value/ref = 普通的值/引用
1)根据下标index注入
<bean id="myBean" class="cn.lzj.constructor.MyBean">
<constructor-arg index="0" value="木兰" />
<constructor-arg index="1" value="18" />
</bean>
2)根据名称name注入
<bean id="myBean" class="cn.lzj.constructor.MyBean">
<constructor-arg name="name" value="木兰" />
<constructor-arg name="age" value="18" />
</bean>
3)根据类型type注入
使用全限定名,类型不能重复
<bean id="myBean" class="cn.lzj.constructor.MyBean">
<constructor-arg type="java.lang.String" value="木兰" />
<constructor-arg type="java.lang.Integer" value="18" />
</bean>
4)自动注入
spring会根据参数的顺序 和值得顺序,自动进行匹配(注意位置要一一对应)
<bean id="myBean" class="cn.lzj.constructor.MyBean">
<constructor-arg value="木兰" />
<constructor-arg value="18" />
</bean>
5)注入内部bean和外部bean
外部bean可以重复使用
<!-- cn.lzj._01_contructor.MyBean 默认找的是类中的无参构造器 -->
<bean id="myBean" class="cn.lzj._01_contructor.MyBean" >
<!-- 利于类中无参构造器,进行设置值 -->
<constructor-arg index="0" value="木兰" />
<constructor-arg index="1" value="15" />
<!-- 构造器中有自定义类的参数值 -->
<!-- 方法1 配置内部bean -->
<constructor-arg>
<bean class="cn.lzj._01_contructor.HisBean" />
</constructor-arg>
<!-- 方法2 引入外部bean-->
<constructor-arg ref="youBean" />
</bean>
<bean id="youBean" class="cn.lzj._01_contructor.YouBean" />
(三) Spring属性注入
(1) 准备一个MyBean
存放普通属性和集合、数组与properties
public class MyBean {
// 普通属性
private Long id;
private String name;
private Boolean sex;
private BigDecimal salary;
// 对象属性
private List<String> list;
private Set<String> set;
private List<OtherBean> otherBeanList;
private Set<OtherBean> otherBeanSet;
//数组与properties
private String[] arrays;
private Properties props1; //Properties:特殊的Map(内部为key-value,要求只能是字符串)
private Properties props2;
getter 、setter 、toString 方法..........
(2) 普通属性注入
配置代码
<!--普通属性 : 配置并设置值-->
<property name="id" value="1" />
<property name="name" value="丁香" />
<property name="sex" value="true" />
<property name="salary" value="123" />
(3) 集合属性注入
- list(可以重复)与set(不允许重复)
- 关键的那个标签(list,set,array),写错也可以用(但不建议)
- 集合内也可以装其他类,然后注入内部bean
配置代码
<!-- list; 有序,可重复-->
<property name="list">
<list>
<value>梅</value>
<value>兰</value>
<value>竹</value>
<value>竹</value>
</list>
</property>
<!-- set; 无序,不可重复-->
<property name="set">
<set>
<value>梅</value>
<value>兰</value>
<value>竹</value>
<value>竹</value>
</set>
</property>
打印效果:
list:[梅, 兰, 竹, 竹]
set:[梅, 兰, 竹]
(4) 数组与properties
- 数组标准写法:
<!--String[] arrays:标准写法-->
<property name="arrays">
<array>
<value>朱雀</value>
<value>玄武</value>
</array>
</property>
- 数组简写
value中的字符串使用",“隔开,所以要求存放的字符串不能有”,"
<!--String[] arrays:简写写法-->
<property name="arrays" value="青龙,白虎" />
- property标准写法(可以支持中文字符)
<!--Properties props1:标准写法(支持中文)-->
<property name="props1">
<props>
<prop key="driver">com.mysql.jdbc.Driver</prop>
<prop key="url">jdbc:mysql:///test</prop>
<prop key="username">root中国人</prop>
</props>
</property>
- property简写
<!--Properties props2:简写形式(不支持中文)-->
<property name="props2">
<value>
driver=com.mysql.jdbc.Driver <!-- 可以使用"=" ,也可以使用隔开 -->
url=jdbc:mysql:///test
username=root中国人
</value>
</property>
(四) Spring全注解注入
(1) 准备三层结构
(2) 配置上下文扫描,并扫描相应的包
- 1.引入context的头
<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">
- 2.启动包扫描机制
使用全注解,需要扫描包下对应类的注解
@Controller : WEB层
@Service : 业务层
@Repository : 持久层
@Component :组件(不知道哪一层,比如util需要让spring进行管理)
@Autowired :注入功能
<context:component-scan base-package="cn.lzj._03_allAnnotations" />
- 3.将dao层注入到service层、service层注入到controller层
@Service
public class UserServiceImpl implements IUserService {
@Autowired
private IUserDao userDao;
----------------------------------------------------------------
@Controller
public class UserControllerImpl implements IUserController {
@Autowired
private IUserService userService;
(3) 处理多个bean类型
- 注解的bean有默认名称(类名【首字母小写】) 如 userDaoImpl
- 修改bean的名称 Component/Service/Repository/Controller(“名称”)
- 在注入bean的时候加上一个限定注解
情景: 一个dao层的接口,有两个实现类
@Repository("userJdbcDao")
public class UserJdbcDaoImpl implements IUserDao{
public void save(){
System.out.println("保存1....");
}
}
-------------------------------------------------------
@Repository("userJpaDao")
public class UserJpaDaoImpl implements IUserDao{
public void save(){
System.out.println("保存2....");
}
}
调用名称的两个方案:
方案一:使用@Autowired
@Service
public class UserService {
@Autowired
@Qualifier("userJdbcDao")
private IUserDao userDao;
public void save(){
userDao.save();
}
}
方案二:使用@Resource
@Service
public class UserService {
@Resource(name="userJpaDao")
private IUserDao userDao;
public void save(){
userDao.save();
}
}
(五) 静态代理模式
代理模式:类似于中介
静态代理模式,即装饰者模式
有三种角色:
① 抽象主题角色
② 真实主题角色
③ 代理主题角色
//通过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
Spring的动态代理
- ①JDK原始动态代理支持(性能好,要求被代理的类必须有实现接口)
- ②CGLIB动态代理支持
(1) 通过XML配置
- 在Spring的xml中导入AOP支持包
<!-- 配置AOP包 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.2.5.RELEASE</version>
</dependency>
- 准备接口: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="cn.itsource._08_xmlaop.EmployeeServiceImpl" />
<!--准备一个事务-->
<bean id="txManager" class="cn.itsource._08_xmlaop.TxManager" />
<!--何时,何地,做什么事-->
<!--代表要做一个AOP的配置-->
<aop:config>
<!--
配置(定义)切点 在哪些类的哪些方法进行功能
id:切点名称(随便取)
expression:表达式(最后定位都是方法)
*:所有返回值
cn.itsource._08_xmlaop:对应的包
I*Service:以I开头,Service结尾的所有接口(所有实现接口的方法)
*:所有方法
(..):所有参数
-->
<aop:pointcut id="pointcut" expression="execution(* cn.lzj._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>
-
测试
查看一下这个对象是否已经被代理
声明必需是接口
测试一下有异常与没有异常的区别
(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="cn.itsource._09_annoaop" />
<!--支持切面的注解-->
<aop:aspectj-autoproxy />
</beans>
-
TxManager
切点的名字是 方法名()
package cn.lzj._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(* cn.itsource._09_annoaop.I*Service.*(..))" />
*/
@Pointcut("execution(* cn.lzj._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();
}
}
}