目录
applicationContext&&BeanFactory
spring 概述
Spring是分层的、JavaSE/EE一站式(full-stack)、轻量级开源框架。 |
spring负责管理项目中的所有对象,是对象的容器,类似于map; |
一站式:只是用spring就可以完成三层架构开发,框架性质属于容器性质,装对象容器 |
以IoC(Inverse Of Control:反转控制)和AOP(Aspect Oriented Programming:面向切面编程)为内核,提供了表现层Spring MVC和持久层Spring JDBC以及业务层事务管理等众多的企业级应用技术,还能整合开源世界众多著名的第三方框架和类库 |
基本spring项目搭建(maven)
目录结构
pom依赖
<?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.bufnali</groupId>
<artifactId>spring_Demo</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.2.0</version>
<scope>compile</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-test -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.1.1.RELEASE</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
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">
<!--将User对象交给Spring容器管理-->
<bean class="cn.bufanli.pojo.User" name="user"></bean>
</beans>
user.java
package cn.bufanli.pojo;
/**
* @author BuShuangLi
* @date 2019/1/10
*/
public class User {
private String Name;
private String id;
private String age;
public String getName() {
return Name;
}
public void setName(String name) {
Name = name;
}
/**
* 初始化方法
*/
public void init() {
System.out.println("spring初始化方法");
}
/**
* 容器销毁方法
*/
public void destroy() {
System.out.println("spring初始化方法");
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
public User(String name, String id, String age) {
Name = name;
this.id = id;
this.age = age;
}
public User() {
}
}
demo.java
package cn.bufanli.Demo;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
/**
* @author BuShuangLi
* @date 2019/1/10
*/
public class Demo {
@Test
public void fun(){
//创建容器对象 从类路径下加载
ApplicationContext ac =new ClassPathXmlApplicationContext("spring/applicationContext.xml");
//创建容器对象 从硬盘绝对路径下加载
//ApplicationContext fileSystemXmlApplicationContext = new FileSystemXmlApplicationContext("d:/xxx/xx/xxx.xml");
//向容器要user对象传入配置文件中Bean标签中name属性值
Object user = ac.getBean("user");
System.out.println(user);
}
}
控制台
SpringIOC概念(反转控制)
我们创建对象的方式反转了,之前是有我们开发人员自己维护,包括依赖关系也是自己new对象 |
使用了Spring之后对象的创建以及依赖关系可以由spring创建以及new |
反转就是之前由我们自己创建反转给了程序(Spring) |
DI(依赖注入)实现IOC思想需要DI支持,
注入方式:
set方法注入 |
构造方法注入 |
字段注入 |
注入类型:
值型类型注入(八大基本数据类型) |
引用类型注入(对象中嵌套另一个对象) |
applicationContext&&BeanFactory
都是spring实例化对象的工厂类
BeanFactory特点 |
|
applicationContext特点 |
|
从类路径下加载配置文件 ApplicationContext ac =new ClassPathXmlApplicationContext("spring/applicationContext.xml"); |
从硬盘决定路径下加载配置文件 //ApplicationContext fileSystemXmlApplicationContext=new FileSystemXmlApplicationContext("d:/xxx/xx/xxx.xml"); |
SpringBean的三重创建对象的方式
第一种方式,上面代码方法
第二、三种方式:
1)创建一个工厂类
package cn.bufanli.Factory;
import cn.bufanli.pojo.User;
/**
* @author BuShuangLi
* @date 2019/1/10
*/
public class UserFactory {
/**
* 静态工厂实例化对象------>第二种方式
* @return
*/
public static User creatUser(){
return new User();
}
/**
* 实例工厂实例化对象------>第三种方式
* @return
*/
public User creatUser2(){
return new User();
}
}
2)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">
<!--将User对象交给Spring容器管理
name: bean标签的表示,也是通过name获取实例对象
class:类的全路径
scope属性:
singleton默认值:单例模式,这个对象再容器中只会存在一个实例
prototype: 多例模式,每次获得是才会创建,并且每次创建的都是新的对象
request:web环境下对象与request生命周期一致
session:web环境下对象与session生命周期一致
init-method
初始化对应方法名
destroy-method="destroy
销毁对应方法名
-->
<!--第一种创建方式-->
<bean class="cn.bufanli.pojo.User" name="user" scope="prototype" init-method="init" destroy-method="destroy"></bean>
<!--第二种创建方式 factory-method方法名其余相同-->
<bean class="cn.bufanli.Factory.UserFactory" name="user2" factory-method="creatUser"></bean>
<!--创建方式三实例工厂创建-->
<!--将工厂交给容器管理-->
<bean class="cn.bufanli.Factory.UserFactory" name="UserFactory" ></bean>
<!--factory-bean="UserFactory" factory-bean属性值为工厂bean标签nama属性值-->
<bean factory-bean="UserFactory" name="user3" factory-method="creatUser2"></bean>
</beans>
分模块配置
<import resource="dataApplication.xml"></import>
属性注入
set方法注入,构造函数注入
<?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">
<!--set方式注入-->
<bean class="cn.bufanli.pojo.User" name="user" scope="prototype">
<!-- 属性注入
为user对象name属性注入value————tom值-->
<property name="name" value="tom"></property>
<!--对象中的对象注入
-->
<property name="car" ref="car"></property>
</bean>
<!--将car对象配置导容器中-->
<bean class="cn.bufanli.pojo.Car" name="car">
<property name="name" value="宏碁"></property>
</bean>
<!--构造函数注入-->
<bean name="user2" class="cn.bufanli.pojo.User">
<constructor-arg name="name" value="22"></constructor-arg>
<constructor-arg name="car" ref="car"></constructor-arg>
<constructor-arg name="id" value="2"></constructor-arg>
<constructor-arg name="age" value="22"></constructor-arg>
</bean>
</beans>
随着项目的启动创建applicationContext类
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">
<!--可以让spring容器随着项目的创建而创建-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!--指定加载spirng配置文件的位置-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/applicationContext.xml</param-value>
</context-param>
</web-app>
注解配置
注解代替配置文件
<?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">
<!--自动扫描Spring中的注解组件-->
<context:component-scan base-package="cn.bufanli"></context:component-scan>
</beans>
代码案例
package cn.bufanli.pojo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;
/**
* @author BuShuangLi
* @date 2019/1/11
* 作用都是将类注入到spring容器
* Component("car") 通用
* Repository("car") dao层与数据库层交互使用
* Controller("car") web层与前端页面交互
* Service("car") service层业务层逻辑代码
*
* Scope 设置单例多例默认是单利
*/
@Component("car")
@Scope(scopeName = "prototype")
public class Car {
/**
* Value 相当于给name属性注入值也可以加到set方法上
*/
@Value("lisi")
private String name;
/**
* Autowired 自动装配对象
* Qualifier 找name为user的对象 指定name 和Autowired配合使用
* Resource 手动注入,指定name为user的对象 指定name单独使用
*/
// @Autowired
// @Qualifier("user")
@Resource(name="user")
private User user;
/**
* 初始化方法 对象创建
*/
@PostConstruct
public void init(){}
/**
* 销毁方法 对象销毁
*/
@PreDestroy
public void destory(){}
/**
* Value
* @param name
*/
//@Value("lisi")
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public Car() {
}
public Car(String name) {
this.name = name;
}
}
SpringJunit测试
package cn.bufanli.pojo;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;
import javax.annotation.Resource;
/**
* RunWith创建容器
* ContextConfiguration 读取配文件位置
*/
@RunWith(SpringRunner.class)
@ContextConfiguration("classpath:spring/applicationContext.xml")
public class UserTest {
@Resource(name="user")
private User u;
@Test
public void tester(){
System.out.println(u.getName());
}
}
Spring AOP
概述:spring能够对容器中管理的对象生成动态代理对象,之前需要手动写动态代理对象,现在需要使用注解或者xml的方式配置
1.动态代理 必须实现接口,才能产生代理对象,如果没有接口将不能实现动态代理对象 |
2.cglib 第三方代理技术,可以对任何类生成代理,代理原理,对目标对象进行继承代理,如果目标对象被final修饰将不能使用cglib代理
|
动态代理代码
代理类
package cn.bufanli.proxy;
import cn.bufanli.service.ServiceImpl.UserServiceImpl;
import cn.bufanli.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* @author BuShuangLi
* @date 2019/1/14
*/
@Component("userServiceProxyFactory")
public class UserServiceProxyFactory implements InvocationHandler {
@Autowired
private UserService userService;
public UserService getUserServiceProxy(){
//生成动态代理对象
UserService o = (UserService)Proxy.newProxyInstance(UserServiceProxyFactory.class.getClassLoader(),
UserServiceImpl.class.getInterfaces(),
// implements InvocationHandler 实现了这个接口
this);
return o;
}
/**
*
* @param proxy 当前代理对象
* @param method 当前调用的方法
* @param args 当前方法执行的参数
* @return
* @throws Throwable
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("打开事务");
Object invoke = method.invoke(userService, args);
System.out.println("提交事务");
return invoke;
}
}
业务层实现类
package cn.bufanli.service.ServiceImpl;
import cn.bufanli.service.UserService;
import org.springframework.stereotype.Service;
/**
* @author BuShuangLi
* @date 2019/1/14
*/
@Service
public class UserServiceImpl implements UserService {
public void save() {
System.out.println("保存用户");
}
public void delete() {
System.out.println("删除用户");
}
public void update() {
System.out.println("更新用户");
}
public void find() {
System.out.println("查询用户");
}
}
测试方法
@Autowired
private UserServiceProxyFactory userServiceProxyFactory;
@Test
public void tester1(){
UserService userServiceProxy = userServiceProxyFactory.getUserServiceProxy();
userServiceProxy.delete();
}
控制台
cglib代理代码
package cn.bufanli.cglib;
import cn.bufanli.service.ServiceImpl.UserServiceImpl;
import cn.bufanli.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cglib.proxy.Callback;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import org.springframework.stereotype.Component;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* @author BuShuangLi
* @date 2019/1/14
*/
@Component("userServiceCglibFactory")
public class UserServiceCglibFactory implements MethodInterceptor {
public UserService getUserServiceCglib(){
//帮助生成代理对象的
Enhancer en = new Enhancer();
//设置代理对象
en.setSuperclass(UserServiceImpl.class);
//设置代理要做什么
en.setCallback(this);
//创建代理对象
UserService us = (UserService)en.create();
return us;
}
/**
*
* @param o 被代理对象
* @param method 被代理对象原始方法
* @param objects
* @param methodProxy
* @return
* @throws Throwable
*/
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
//打开事务
System.out.println("打开事务");
//调用原有方法
Object o1 = methodProxy.invokeSuper(o, objects);
//提交事务
System.out.println("提交事务");
return o1;
}
}
测试类
@Autowired
private UserServiceCglibFactory userServiceCglibFactory;
@Test
public void tester2(){
UserService userServiceCglib = userServiceCglibFactory.getUserServiceCglib();
userServiceCglib.delete();
}
Joinpoint(连接点): | 目标对象中可以增强的方法叫连接点 |
Pointcut(切入点): | 目标对象中已经增强的方法,可以针对某一个方法进行增强 |
Advice(通知.增强): | 增强的方法 |
Target(目标对象): | 被代理对象 |
WeAVing(植入): | 将通知应用到切入点的过程 |
Proxt(代理): | 将通知植入带目标对象形成代理对象 |
Aspect(切面): | 切入点+通知 |
Spring中AOP使用
导入依赖
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.13</version>
</dependency>
<!-- aspectj支持 -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.8.9</version>
</dependency>
通知类
package cn.bufanli.aspect;
import org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint;
/**
* @author BuShuangLi
* @date 2019/1/14
* 通知类
*/
public class MyActive {
//前置通知-->在目标方法运行之前调用
//后置通知(如果出现异常不会调用)-->在目标方法运行之后调用
//环绕通知-->在目标方法之前和之后都调用
//异常类拦截通知-->如果出现异常就会调用通知代码
//后置通知(无论是否出现异常都会调用)-->在目标方法运行之后调用
/**
* 前置通知
*/
public void before(){
System.out.println("前置通知");
}
/**
* 后置通知-->如果出现异常不会调用
*/
public void afterReturning(){
System.out.println("后置通知(如果出现异常不会调用)");
}
/**
* 环绕通知
*/
public Object around(MethodInvocationProceedingJoinPoint proceedingJoinPoint){
Object proceed = null;
try {
//调用目标方法
System.out.println("环绕通知之前");
//调用目标方法
proceed=proceedingJoinPoint.proceed();
System.out.println("环绕通知之后");
} catch (Throwable throwable) {
throwable.printStackTrace();
}
return proceed;
}
/**
* 异常通知
*/
public void afterException(){
System.out.println("异常通知");
}
/**
* 后置通知-->出现异常也会调用
*/
public void after(){
System.out.println("后置通知-->出现异常也会调用");
}
}
配置文件
<?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">
<!--自动扫描Spring中的注解组件-->
<context:component-scan base-package="cn.bufanli"></context:component-scan>
<!--aop-->
<!--配置目标对象-->
<bean class="cn.bufanli.service.ServiceImpl.UserServiceImpl" name="userService"></bean>
<!--配置通知对象-->
<bean class="cn.bufanli.aspect.MyActive" name="myActive"></bean>
<!--将配置通知类绑定到目标对象-->
<aop:config>
<!--配置切入点
expression: 切点表达式
原始:
public void cn.bufanli.service.ServiceImpl.UserServiceImpl.save()
<aop:pointcut id="pc" expression="execution(public void cn.bufanli.service.ServiceImpl.UserServiceImpl.save())"></aop:pointcut>
改进:
public可以省略 void 可以为 * 表示对返回值不做要求
UserServiceImpl *ServiceImpl 表示已什么结尾
save() save(..) 表示对方法内的参数不做要求
<aop:pointcut id="pc" expression="execution( * cn.bufanli.service.ServiceImpl.*ServiceImpl.save(..))"></aop:pointcut>
-->
<aop:pointcut id="pc" expression="execution( * cn.bufanli.service.ServiceImpl.*ServiceImpl.save(..))" ></aop:pointcut>
<aop:aspect ref="myActive">
<!--前置通知-->
<aop:before method="before" pointcut-ref="pc"></aop:before>
<!--后置异常-->
<aop:after-returning method="afterReturning" pointcut-ref="pc"></aop:after-returning>
<!--环绕通知-->
<aop:around method="around" pointcut-ref="pc" ></aop:around>
<!--异常拦截通知-->
<aop:after-throwing method="afterException" pointcut-ref="pc"></aop:after-throwing>
<!--后置通知-->
<aop:after method="after" pointcut-ref="pc"></aop:after>
</aop:aspect>
</aop:config>
</beans>
测试
package cn.bufanli.pojo;
import cn.bufanli.service.UserService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.junit4.SpringRunner;
import javax.annotation.Resource;
/**
* RunWith创建容器
* ContextConfiguration 读取配文件1位置
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:spring/applicationContext.xml")
public class UserTest {
@Resource(name = "userService")
private UserService userService;
@Test
public void tester3(){
userService.save();
userService.find();
userService.delete();
userService.update();
}
}