优点
- spring是一个开源的免费的框架(容器)
- spring是一个轻量级的,非入侵式的框架
- 控制反转(IOC)面向切面编程(AOP)
- 支持事务处理,对框架整合的支持
== 总结 :Spring就是一个轻量级的控制反转和面向切面编程的框架==
1.导包
导这个spring-webmvc Maven就自动帮助导入了其他的包
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.0.RELEASE</version>
</dependency>
整合Mybatis
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.0.RELEASE</version>
<scope>compile</scope>
</dependency>
所有版本的下载地址https://repo.spring.io/ui/native/release/org/springframework/spring
Maven查找导包地址 https://mvnrepository.com/
https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#spring-core
2.Bean
配置文件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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="user" class="cn.liu.bean.User">
<property name="age" value="1"></property>
</bean>
User user = new User();
↑
<bean id="实体名" class="实体路径"> 但不局限于实体
实体属性 ref="引用Spring容器中创建好的对象" value="要传递的具体数值参数",基本数据类型用这个
<property name="实体属性名" value=""></property>
</bean>
<bean id="" class=""> 上面那个注册好的bean id
<property name="属性" ref="user"></property>
</bean>
<bean id="" class="">
<constructor-arg ></constructor-arg>
</bean>
起别名
<alias name="原名" alias="别名"></alias>
通过name,可以起多个别名
<bean id="user" class="cn.liu.bean.User" name="user1,user2">
</bean>
</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"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
指定扫描特定的包,使之注解生效,因情况而写
<context:component-scan base-package="cn.liu.bean"/>
注解驱动注解开启
<context:annotation-config/>
</beans>
使用的时候实现类,ApplicationContext context = new ClassPathXmlApplicationContext(“…xml”,“…xml”);
context.getBean()
固定写法
@Test
public void test1()
{
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
//通常是这样,自动生成的是
Object student = context.getBean("student")
//Student student = context.getBean("student", Student.class);Student.class是固定写死了
System.out.println(student.toString());
}
进阶/拓展
团队项目开发如有多个beans文件,想要汇总到applicationContext.xml,最后只用这一个
在applicationContext.xml中
<import resource="beans1.xml"></import>张三写的
<import resource="beans2.xml"></import>李四写的
<import resource="beans3.xml"></import>王五写的
id相同会被覆盖
控制他可以创建几个对象
<bean id="user" class="cn.liu.bean.User" scope="单例Singleton,原型prototype">
</bean>
1.使用无参构造创建对象,默认
2.有参(没有无参构造器)
- 1.下标赋值
package cn.liu.bean;
public class User {
private String name;
private int age;
public User(String name, int age) {
this.name = name;
this.age = age;
}
get/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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="user" class="cn.liu.bean.User">
<constructor-arg index="0" value="lzk"></constructor-arg>
<constructor-arg index="1" value="18"></constructor-arg>
</bean>
</beans>
- 2.通过类型 不建议使用
<constructor-arg type="java.lang.String" value="liu"/>
<constructor-arg type="int" value="18"/>
-
3.直接用参数名
<constructor-arg name="age" value="18"></constructor-arg> <constructor-arg name="name" value="liu"></constructor-arg>
总结:在配置文件被加载的时候,所有的bean都会被创建,而且只创建一份(单例)
复杂数据类型注入
public class Address {
private String address;
get/set
}
public class Student {
private String name;
private Address address;//引用类型
private String[] books;
private List<String> hobbies;
private Map<String,String> card;
private Set<String> games;
private String wife;//设置空指针,有没有
private Properties info;//配置类,里面可以自定义
get/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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="address" class="cn.liu.bean.Address">
<property name="address" value="abcd"/>
</bean>
<bean id="student" class="cn.liu.bean.Student">
<!--普通注入,value-->
<property name="name" value="liu"></property>
<!--Bean注入,ref-->
<property name="address" ref="address"></property>
<!--数组注入-->
<property name="books">
<array>
<value>《水浒传》</value>
<value>《红楼梦》</value>
</array>
</property>
<!--list注入-->
<property name="hobbies">
<list>
<value>听歌</value>
<value>游泳</value>
</list>
</property>
<!--Map-->
<property name="card">
<map>
<entry key="身份证" value="123132"></entry>
<entry key="银行卡" value="1314156"/>
</map>
</property>
<!--set-->
<property name="games">
<set>
<value>LOL</value>
<value>CF</value>
</set>
</property>
<!--设置null值-->
<!--
空串
<property name="wife" value=""/>或者↓
-->
<property name="wife">
<null/>
</property>
<!--Properties-->
<property name="info">
<props>
<prop key="driver">123123</prop>
<prop key="url">123132</prop>
<prop key="username">1231</prop>
</props>
</property>
</bean>
</beans>
@Test
public void test1()
{
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
//通常是这样,自动生成的是
Object student = context.getBean("student")
System.out.println(student.toString());
}
结果
Student{name='liu', address=Address{address='abcd'}, books=[《水浒传》, 《红楼梦》], hobbies=[听歌, 游泳], card={身份证=123132, 银行卡=1314156}, games=[LOL, CF], wife='null', info={url=123132, driver=123123,username=1231}}
自动装配
1.xml里面autowire
<bean id="address" class="cn.liu.bean.Address">
<property name="address" value="abcd"/>
</bean>
<bean id="student" class="cn.liu.bean.Student" autowire=" "></bean>
值
byName:找id和set后面方法名一样的,缺点:id名字要一样address,address123就不行了
byType:找类一样的,缺点:不能创建多个<bean id="address1"...><bean id="address2"...>就不行了
2.注解
使用注解
- 导入约束 context
- 配置注解支持<context:annotation-config/>
- 指定扫描特定的包,使之注解生效<context:component-scan base-package=“cn.liu.bean”/>
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
指定扫描特定的包,使之注解生效,因情况而写
<context:component-scan base-package="cn.liu.bean"/>
注解驱动注解开启
<context:annotation-config/>
</beans>
①直接在属性上@Autowired,也可以用在set方法上
使用@Autowired时,可以不写set方法,@Autowired默认先按Type进行匹配,如果找到多个bean,则又会按照组件id方式进行匹配(需要@Qualifier(“name”)配合,显式的指定一个)。
②@Resource(name=“”)名字id标准的话可以不写括号,它是java中带的,各有各的好处,它可以实现相同的功能
拓展:
允许属性为null
- @Autowired(required = false),true就是不允许
- @Nullable 允许为null
区别
@Resource 注解和@Autowired注解作用比较相似,也是实现组件的自动注入。它是JAVA2EE提供的注解,使用的时候需要导入javax.annotation.Resourc 。
@Resource默认按照组件id自动注入,如果按照默认组件id找不到bean时,再按照类型去匹配。
例一
public class Student {
private String name;
@Autowired
private Address address;//引用类型
}
<context:annotation-config/>
<bean id="address" class="cn.liu.bean.Address"/>
<bean id="student" class="cn.liu.bean.Student"/>
3.使用注解开发
在spring 4 之后,使用注解开发必须保证aop的包的导入
@Component 相当于 把类放到容器中
@Component(“Stu”) id名就是Stu
例:
@Component
public class Student {
private String name;
@Autowired
private Address address;//引用类型
}
在xml里面就不用写<bean id="student" class="cn.liu.bean.Student"/>
衍生的注解:
和@Component的功能一样
- dao层@Repository
- service层@Service
- controller层@Controller
4.使用Java的方式配置Spring(自定义)
完全不用XML了,全权交给Java来做
JavaConfig是Spring的一个子项目,在Spring 4 之后成为核心功能
- new ClassPathXmlApplicationContext(“beans.xml”);
- new AnnotationConfigApplicationContext(LiuConfig.class);
- @Configuration 相当于Beans
- @CompoentScan(“cn.liu”)扫描
- @Import(…)导入别的Config
@Component
public class User {
private String name;
@Autowired
private Address address;//引用类型
public String getName() {
return name;
}
@Value("123")
public void setName(String name) {
this.name = name;
}
......
}
public class Address {
@Value("123")
private String address;
......
}
@Configuration 相当于Beans
public class LiuConfig {
@Bean 方法名getUser相当于id
public User getUser(){
return new User();
}
@Bean
public Address getAddress(){
return new Address();
}
}
ApplicationContext context = new AnnotationConfigApplicationContext(LiuConfig.class);
Object getUser = context.getBean("getUser");
System.out.println(getUser.toString());
5.AOP
代理模式,AOP的底层
5.1静态代理
角色分析:
- 抽象角色:一般会使用接口或者抽象类解决
- 真实角色:被代理的角色
- 代理角色:代理真实的角色,代理后,一般会做一些附属操作
- 客户:访问代理对象的人
5.2动态代理(代理的是接口重点)
5.3真实实现
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Si5UYlK6-1688618521167)(D:\笔记资料\JavaEE笔记\imgs\4.JPG)]
导入织入包
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.19</version>
<scope>runtime</scope>
</dependency>
配置文件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"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<context:component-scan base-package="cn.liu"/>
<context:annotation-config/>
<!--配置aop-->
<aop:config>
</aop:config>
</beans>
例子1:使用Spring API接口:
配置文件
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<context:component-scan base-package="cn.liu"/>
<context:annotation-config/>
<!--配置aop-->
<!--方式1 使用Spring API接口-->
<aop:config>
<!--切入点:execution(要执行的位置 修饰词 返回类型 类名 方法名 参数)-->
<!--详细查Aspectj切入点语法定义
* 表示返回任意类型
cn..包名
.*表示这个类下所有方法
(..) 表示可以有任意个参数
-->
<aop:pointcut id="pointcut" expression="execution(* cn.liu.service.UserServiceImpl.*(..))"/>
<!--执行环绕增加 动态代理生成一个代理对象 哪个类,切入到哪里-->
<aop:advisor advice-ref="beforeLog" pointcut-ref="pointcut"/>
<aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>
</aop:config>
</beans>
-------------------------------------------------------------------------------------------------
@Component
public class BeforeLog implements MethodBeforeAdvice {
/**
*method:要执行的目标方法
* args:参数
* target:目标对象
*/
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println(target.getClass().getName()+"的"+method.getName()+"被执行了");
}
}
-------------------------------------------------------------------------------------------------
@Component
public class AfterLog implements AfterReturningAdvice {
@Override
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println("执行了"+method.getName()+"方法,返回了"+returnValue);
}
}
-------------------------------------------------------------------------------------------------
public interface UserService {
public void add();
public void delete();
public void update();
public void select();
}
-------------------------------------------------------------------------------------------------
@Component
public class UserServiceImpl implements UserService {
@Override
public void add() {
System.out.println("增加了一个用户");
}
@Override
public void delete() {
System.out.println("删除了一个用户");
}
@Override
public void update() {
System.out.println("更新了一个用户");
}
@Override
public void select() {
System.out.println("查询了一个用户");
}
}
-------------------------------------------------------------------------------------------------
实现类
@Test
public void test1()
{
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
/**
*谨记切记此处一个重点,动态代理是代理接口,也就是说 UserService.class而不是实现类
*/
UserService userService = context.getBean("userServiceImpl", UserService.class);
userService.add();
}
-------------------------------------------------------------------------------------------------
结果
cn.liu.service.UserServiceImpl的add被执行了
增加了一个用户
执行了add方法,返回了null
例子2:自定义
配置文件
<aop:config>
<!--自定义切面(aspect切面),ref 要引用的类-->
<aop:aspect ref="diy">
<aop:pointcut id="pointcut" expression="execution(* cn.liu.service.UserServiceImpl.*(..))"/>
<aop:before method="before" pointcut-ref="pointcut"/>
<aop:after method="after" pointcut-ref="pointcut"/>
</aop:aspect>
</aop:config>
新增
package cn.liu.diy;
import org.springframework.stereotype.Component;
@Component("diy")
public class DiyPointCut {
public void before(){
System.out.println("方法执行前");
}
public void after(){
System.out.println("方法执行后");
}
}
例子3:注解实现
需要导包
<!-- https://mvnrepository.com/artifact/aspectj/aspectjrt -->
<dependency>
<groupId>aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.5.4</version>
</dependency>
@Aspect 相当于上例 <aop:aspect ref=“diy”>
@Before(“execution(…)”)不要导错包,junit包下也有,要导aspectj包
需要配置文件
开启注解支持
<aop:aspectj-autoproxy/>
注意此处需要将他放进去@Component
@Component
@Aspect
public class AnnotationPointCut {
@Before("execution(* cn.liu.service.UserServiceImpl.*(..))")
public void before(){
System.out.println("方法执行前");
}
@After("execution(* cn.liu.service.UserServiceImpl.*(..))")
public void after(){
System.out.println("方法执行后");
}
}
tifact/aspectj/aspectjrt -->
aspectj
aspectjrt
1.5.4
@Aspect 相当于上例 <aop:aspect ref="diy">
@Before("execution(..........)")不要导错包,junit包下也有,要导aspectj包
需要配置文件
```xml
开启注解支持
<aop:aspectj-autoproxy/>
注意此处需要将他放进去@Component
@Component
@Aspect
public class AnnotationPointCut {
@Before("execution(* cn.liu.service.UserServiceImpl.*(..))")
public void before(){
System.out.println("方法执行前");
}
@After("execution(* cn.liu.service.UserServiceImpl.*(..))")
public void after(){
System.out.println("方法执行后");
}
}