spring简介
spring是一个轻量级的java开源的框架,使用java语言编写。其核心技术是:IOC,AOP。spring的作用是解决java对象之间的耦合,解决模块模块之间的耦合。spring又叫做:容器, spring作为容器, 装的是java对象。 可以让spring创建java对象, 给属性赋值。
spring容器
Spring优点
Spring 是一个框架,是一个半成品的软件。有 20 个模块组成。它是一个容器管理对象,容器是装东西的,Spring 容器不装文本,数字。装的是对象。Spring 是存储对象的容器。
(1) 轻量
Spring 框架使用的 jar 都比较小,一般在 1M 以下或者几百 kb。Spring核心功能的所需的 jar 总共在 3M 左右。
Spring 框架运行占用的资源少,运行效率高。不依赖其他 jar
(2) 针对接口编程,解耦合
Spring 提供了 Ioc 控制反转,由容器管理对象,对象的依赖关系。原来在程序代码中的对象创建方式,现在由容器完成。对象之间的依赖解耦合。
(3) AOP 编程的支持
通过 Spring 提供的 AOP 功能,方便进行面向切面的编程,许多不容易用传统 OOP 实现的功能可以通过 AOP 轻松应付在 Spring 中,开发人员可以从繁杂的事务管理代码中解脱出来,通过声明式方式灵活地进行事务的管理,提高开发效率和质量。
(4) 方便集成各种优秀框架
Spring 不排斥各种优秀的开源框架,相反 Spring 可以降低各种框架的使用难度,Spring 提供了对各种优秀框架(如 Struts,Hibernate、MyBatis)等的直接支持。简化框架的使用。Spring 像插线板一样,其他框架是插头,可以容易的组合到一起。需要使用哪个框架,就把这个插头放入插线板。不需要可以轻易的移除。
IOC的理解
IoC,Inversion of Control:控制反转。在Java开发中,Ioc意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制。
DI:Dependency Injection.依赖注入。开发者只需要提供要使用的对象名称就可以了。对象如何创建,如何查找,都是由Spring容器内部实现。
核心代码
//自主控制bean
SomeService someService1 = new SomeServiceImpl();
someService1.doSome();
//把bean交给spring管理
//获取配置bean文件,spring容器在加载bean配置文件时就已经创建好了其中的所有bean,等到后续程序要
//用的时候就会直接用,创建好的bean是会放在内存里面。
ApplicationContext applicationContext =
new ClassPathXmlApplicationContext("userBean.xml");
//拿到bean,强制转换,父类的引用指向子类的对象
Student studentInfo = (Student) applicationContext.getBean("studentInfo");
//获取注入的bean的实体类信息
System.out.println("姓名:"+studentInfo.getName()+"年龄:"+studentInfo.getAge()+"学校:"+studentInfo.getSchool().getName());
<!--在xml设置bean属性需要实体类中实现set方法-->
<bean name="studentInfo" class="com.study.component.Student">
<property name="name" value="张三"></property>
<property name="age" value="18"></property>
<!--配置对象属性-->
<property name="school" ref="mySchool"/>
</bean>
<bean name="mySchool" class="com.study.component.School">
<property name="name" value="县三中"></property>
<property name="address" value="西渡"></property>
</bean>
常用注解及介绍
@component:定义java对象,需要在配置文件(<context:component-scan base-package=“注解所在的包名”/>)中指定需要扫描的包,不然不会生效
@Respository:dao层,持久层对象,表示独享能访问数据库。
@Service :service对象,业务层对象,处理业务逻辑,具有事物能力。
@Controller : 控制器对象, 接收请求,显示请求的处理结果。 视图层对象
@Autowired与@Resouce
@Autowired(required = false)
@Qualifier(“mySchool”)//指定bean name注入@Resouce(“beanName”)(需要指定beanName)与Autowired这两个注解结合的一致。
用来给引用类型赋值的注解,直接放在引用类型上面。
@Autowired(required = false)默认required = true表示这个这个在注入的时候找不到bean导致引用类型失败,程序会报错。而改为false之后注入失败程序不会报错,但注入的引用类型的值就会为空。
注意:@Resouce是java 自带的包,且1.8版本之后的java已不支持此注解。@Autowired是Spring内部的jar包,导入相关依赖就可以使用。
AOP的理解
Aspect Orient Programming(面向切面编程)
aspect:切面,可以在不影响应用程序的情况下,对当前程序增加业务功能,使程序可复用性变强。一般用在:日志功能,事务功能,权限验证。
AOP中的术语
1)Aspect:切面, 给业务方法增加的功能。
2)JoinPoint:连接点, 连接切面的业务方法。 在这个业务方法执行时,会同时执行切面的功能。
3)Pointcut: 切入点, 是一个或多个连接点集合。 表示这些方法执行时,都能增加切面的功能。
表示切面执行的位置。
4)target: 目标对象, 给那个对象增加切面的功能, 这个对象就是目标对象。
5)Advice:通知(增强),表示切面的执行时间。 在目标方法之前执行切面,还是目标方法之后执行切面。
AOP中重要的三个要素
Aspect, Pointcut , Advice. 这个概念的理解是: 在Advice的时间,在Pointcut的位置, 执行Aspect
代码表示
采用的jar包,manven如下:
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.0</version>
</dependency>
<!--日志文件管理包——logStart-->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<!--AOP 包 start-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.8.8</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.3</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.11.1</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.11.2</version>
</dependency>
<!--AOP end-->
<dependency> <groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
aopBean.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:aop="http://www.springframework.org/schema/aop"
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/aop https://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<bean name="loginService" class="com.study.aop.service.impl.LoginServiceImpl"></bean>
<bean name="registerService" class="com.study.aop.service.impl.RegisterServiceImpl"></bean>
<!-- 声明切面类-->
<bean name="myAspect" class="com.study.aop.handle.MyAspect"></bean>
<context:component-scan base-package="com.study.aop.service.impl"></context:component-scan>
<!--声明自动代理-->
<aop:aspectj-autoproxy/>
</beans>
MyAspect 切面类
需要注意的是这个表达式(execution后面需要接修饰符、 参数返回值、 然后就是指定类名(可用代替)、参数可有可无、异常(此例没有体现))
execution(public void com.study.aop.service.impl..user*(String,String))
/**
* @author lx
*
* 创建切面类
*/
@Aspect
public class MyAspect {
//切面方法必须是public、 void、 无参(有参必须是JoinPoint类型)的
//执行的execution必须是基本数据类型+String
// @Before(value = "execution(public void com.study.aop.service.impl.LoginServiceImpl.userLogin*(String,String))")
// public void myBefore(){
// System.out.println("这个是前置通知******执行了前置业务"+new Date());
// }
//可以带参,必须时候JoinPoint
@Before(value = "execution(public void com.study.aop.service.impl.*.user*(String,String))")
public void myBefore(JoinPoint joinPoint){
System.out.println("连接点的方法定义:"+joinPoint.getSignature());
System.out.println("连接点方法的参数个数:"+joinPoint.getArgs().length);
System.out.println("这个是前置通知******执行了前置业务"+new Date());
}
//在目标方法执行之后执行。
@AfterReturning(value = "execution(public void com.study.aop.service.impl.*.user*(String,String))")
public void myAfter(JoinPoint joinPoint){
System.out.println("连接点的方法定义:"+joinPoint.getSignature());
System.out.println("连接点方法的参数个数:"+joinPoint.getArgs().length);
System.out.println("这个是后置通知******执行了后置业务"+new Date());
}
}
loginService及其实现类(还有个注册及其实现类,实现方法都一样就没添加了)
/**
* @author lx
*/
public interface LoginService {
/**
*
* @return
* 用户登录
* 用户登录信息
*/
void userLogin(String name,String passWord);
}
/**
* @author lx
* 登录实现类
*/
public class LoginServiceImpl implements LoginService {
@Override
public void userLogin(String name,String password) {
System.out.println("======================");
System.out.println("执行用户登录业务"+"用户名:"+name+",密码:"+password);
System.out.println("======================");
}
public void userLoginOf() {
System.out.println("执行用户登录之后的业务");
}
}
测试类
/**
* @author lx
*/
public class ApplicationRun {
public static void main(String[] args) {
String beansPath ="aopBean.xml";
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(beansPath);
LoginService loginService = (LoginService)applicationContext.getBean("loginService");
RegisterService registerService = (RegisterService)applicationContext.getBean("registerService");
registerService.userRegister("zhansan","123456");
loginService.userLogin("zhansan","123456");
//LoginService loginService = new LoginProxyImpl();
//loginService.userLogin("zhansan","123456");
}
}
环绕通知Around
在执行业务方法之前和之后增加功能,可以用来记录日志或者处理事务,比前置通知跟后置通知更加灵活。
优点:
可以在执行方法的前后都增加功能。
可以控制方法是否执行。
可以修改目标方法的返回值。
//@Around()
//环绕通知可以有返回值,可以包含ProceedingJoinPoint类型的一个参数
@Around("execution(* *com.study.aop.service.impl.*.do*(String))")
public Object doSome(ProceedingJoinPoint joinPoint) throws Throwable {
Object object = null;
System.out.println("执行了环绕通知,在目标方法之前执行,可以输出日志");
//proceed()方法会调用目标方法
Object proceed = joinPoint.proceed();
System.out.println("执行了环绕通知,在执行方法之后执行,可以处理事物");
//如果需要修改目标方法的返回值,需要return 你想return的结果。不想修改的话可以直接返回proceed
return "myAspect 的 Around";
}
测试类
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("aopBean.xml");
DoServiceByAround doService = (DoServiceByAround) applicationContext.getBean("doService");
//这个返回结果实际是myaspect 下面环绕通知方法Around的返回结果,不是dosome方法的
String str = doService.doSome("hello");
System.out.println("调用之后的返回结果"+str+"=======");
}