1.Spring是一个分层的全栈式轻量级开发框架,以IOC和AOP为核心
2.IOC控制反转将创建对象的工作交给Spring框架。DI依赖注入负责具体实现创建对象的过程
3.导入jar包后,根据需求配置xml文件
public interface Dao {
public void excute();
}
public class DaoImpl1 implements Dao{
@Override
public void excute() {
System.out.println("DaoImpl1");
}
}
<?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">
<bean id="DaoImpl1" class="Dao.DaoImpl1">
</bean>
</beans>
创建对象:
ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
Dao dao=(Dao) context.getBean("DaoImpl1");
dao.excute();
需要变更直接将xml文件中,<bean>标签属性中class的值改变即可,不需要改动代码
4.bean标签属性详解
id:定位对象唯一标识
class:定位要创建对象的类所在位置
lazy-init:默认false,懒加载。初始化时就已经把配置文件的对象创建好并收入到容器中。配为true,则在调用getBean方法时才会创建
scope: singlon(默认) - 单例
prototype - 多例
request - 每一次http请求都会生成一个对象,仅在当前请求有效,请求完毕随即销毁。
session - 每一次http请求都会生成一个对象,仅在当前session有效,session销毁对象随即销毁。
init-method:指定对象初始化时需要执行的方法
autowire: byName 通过对象中属性名寻找容器中id一致的属性进行注入
byType 通过对象中属性类型寻找容器中class一致的属性进行注入(将要注入的属性在容器中声明只允许纯在一个)
5.可以通过构造方法注入对象的属性值
public class Person {
private Integer userid;
private String username;
private String password;
@Override
public String toString(){
String result = "User:{userid="+userid+",username="+username+",password="+password+"}";
return result;
}
public Person(){
}
public Person(Integer userid, String username, String password) {
System.out.println("BuildPerson");
this.userid = userid;
this.username = username;
this.password = password;
}
public void setUserid(Integer userid) {
System.out.println("setUserid");
this.userid = userid;
}
public void setUsername(String username) {
System.out.println("setUsername");
this.username = username;
}
public void setPassword(String password) {
System.out.println("setPassword");
this.password = password;
}
}
public class Company {
Person p;
public void setP(Person p) {
this.p = p;
}
}
<bean id="person2" class="Entity.Person">
<constructor-arg name="userid" value="2"/>
<constructor-arg name="username" value="cccc"/>
<constructor-arg name="password" value="dddd"/>
</bean>
当对象属性存在set方法时,可以通过<property></property>标签注入
<--对象person>
<bean id="person" class="Entity.Person">
<!--文本注入,可以忽略特殊字符-->
<property name="userid">
<value><![CDATA[11]]></value>
</property>
<property name="username" value="aaaa"></property>
<property name="password">
<value>bbbb</value>
</property>
</bean>
<--对象Company>
<bean id = "company" class="Entity.Company">
<!-- 引用类型注入 -->
<property name="p">
<bean id = "person" class = "Entity.Person"></bean>
</property>
<!-- 数组注入 -->
<property name="arr">
<array>
<value>1</value>
<value>2</value>
</array>
</property>
<!-- list注入基础类型 -->
<property name="list">
<list>
<value>JAVA</value>
<value>JAVA</value>
</list>
</property>
<!-- list注入引用类型 -->
<property name="listObj">
<list>
<bean id = "person11" class="Entity.Person"></bean>
<bean id = "person22" class="Entity.Person"></bean>
<ref bean="person"></ref>
</list>
</property>
<!-- set注入基础类型 -->
<property name="set">
<set>
<value>1</value>
<value>2</value>
</set>
</property>
<!-- set注入引用类型 -->
<property name="setObj">
<set>
<bean id = "person33" class="Entity.Person"></bean>
<bean id = "person44" class="Entity.Person"></bean>
<ref bean="person"></ref>
</set>
</property>
<!-- map注入基础类型 -->
<property name="map">
<map>
<entry key="1" value="1"></entry>
<entry key="2" value="2"></entry>
<entry key="3" value="3"></entry>
</map>
</property>
<!-- map注入引用类型-->
<property name="mapObj">
<map>
<entry key-ref="person" value-ref="person2"></entry>
<entry>
<key>
<bean id = "person55" class="Entity.Person">
<property name="userid" value="55"></property>
</bean>
</key>
<bean id = "person66" class="Entity.Person">
<property name="userid" value="66"></property>
</bean>
</entry>
</map>
</property>
</bean>
6.自建工厂
import org.springframework.beans.factory.FactoryBean;
/**
* 自建工厂,实现FactoryBean接口
*/
public class CompanyFactory implements FactoryBean<Company> {
@Override
public Company getObject() throws Exception {
System.out.println("通过自建工厂返回实例");
return new Company();
}
@Override
public Class<?> getObjectType() {
return Company.class;
}
}
/**
* 配置文件
*/
<bean id="company2" class="Entity.CompanyFactory"></bean>
/**
* 创建对象代码
*/
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Company company = context.getBean("company2",Company.class);
执行结果:
通过自建工厂返回实例
可以看到,配置文件虽然注入的是CompanyFactory类,返回的确是company对象。其实这一步本质上也是框架替我们做的。
6.Bean的生命周期
1.配置对象
2.注入属性
3.执行初始化方法
4.获得对象
5.销毁对象
如果想对全局对象在初始化方法执行前/执行后添加操作,可以配置一个或多个后置处理器(类似于代理模式)
/**
* 后置处理器
*/
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("初始化方法执行前");
return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("初始化方法执行后");
return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
}
}
<!-- 注册后置执行器-->
<bean id="mybeanpostprocessor1" class="Entity.MyBeanPostProcessor"></bean>
7.Spring引入外部配置文件
首先需要引入context命名空间
新增
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"
变成
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"
配置文件内容
test_userid=1
test_username=aaa
test_password=bbb
<!--引入配置文件-->
<context:property-placeholder location="classpath:test.properties"></context:property-placeholder>
<!--注入属性-->
<bean id="person" class="Entity.Person">
<property name="userid" value="${test_userid}"></property>
<property name="username" value="${test_username}"></property>
<property name="password" value="${test_password}"></property>
</bean>
8.注解实现IOC和DI
注解实现创建对象可以免去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
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="Annotation"></context:component-scan>
</beans>
8 类注解:使用该注解的类都可以通过容器创建对象
@Component :通用注解
@Controller:Controller层注解
@Service:Service层注解
@Repository:持久化层注解
/**
* 自定义id,默认id类名首字母小写,下面例子就是testController
*/
@Controller("tesController")
public class TestController {
public TestController() {
System.out.println(1);
}
}
可以通过配置XML文件指定扫描的注解范围
<!--
use-default-filters:false不启用默认过滤器
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
:扫描Controller类型注解
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service"/>
:不扫描Service注解
-->
<context:component-scan base-package="Annotation" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service"/>
</context:component-scan>
获得对象
//获得配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("Annotation.xml");
//获得对象,ID是注解所在的类的类名首字母小写,也可以自定义id
TestController controller = context.getBean("testController",TestController.class);
通过注解实现DI
@Service
public interface UserService {
void add();
}
@Service
public class UserServiceImpl implements UserService {
@Autowired
UserDao userDao;
@Override
public void add() {
System.out.println("UserServiceImpl");
userDao.add();
}
}
@Repository
public interface UserDao {
void add();
}
@Repository
public class UserDaoImpl1 implements UserDao {
@Override
public void add() {
System.out.println("UserDapImpl1");
}
}
@Autowired:自动注入属性,当该属性在扫描范围内只有一个实现类时才能使用,当有多个实现类时,需要再加上@Qualifier("userDaoImpl2")注解指定实现类名称
@Repository
public class UserDaoImpl2 implements UserDao {
@Override
public void add() {
System.out.println("UserDapImpl2");
}
}
@Service
public class UserServiceImpl implements UserService {
@Autowired
@Qualifier("userDaoImpl2")
UserDao userDao;
@Override
public void add() {
System.out.println("UserServiceImpl");
userDao.add();
}
}
@Resource(name="userDaoImpl2");可以实现一个注解完成上面两个注解的工作,如果只有一个实现类则不需要指定名字,但这个注解是javax.annotation包下的,不是spring的
基础属性赋值:通过value注解
@Value("111")
private String str1;
@Value("${test_str2}")
private String str2;
<context:property-placeholder location="annotation.properties"></context:property-placeholder>
9.AOP
AOP是Spring的利用动态代理实现面向切面编程,随时可以在执行A方法之前/之后添加新的方法
9.1 术语解析
连接点(joint point): 原始对象中允许被增强的方法。
切入点(PointCut): 原始对象中实际被增强的方法。
通知(Advice): 代理对象中新加入的功能
通知类型:
前置通知:切入点前执行的通知
后置通知:切入点后执行的通知,切入点执行异常则不执行后置通知
环绕通知:切入点前后都要执行的通知
异常通知:切入点发生异常时要执行的通知
最终通知:在切入点执行完毕之后执行的通知,无论是否发生异常
目标对象(Target): 被增加功能的对象(被代理对象)
切面(Aspect): 将所有通知组合成一个类,就是切面。每个通知都要指定自己的切入点范围
织入(Weaving): 生成代理对象并执行代理方法的过程
切入点表达式:通过表达式指定切入点的位置,用于建立通知和切入点之间的联系
excution([权限修饰符] [返回值类型(可以省略)] [类的全路径名] [方法名] [参数列表])
excution(* com.aop.User.add(..)) 切入User类的add方法上
excution(* com.aop.User.*(..)) 切入User类的所有方法上
excution(* com.aop.*.*(..)) 切入aop包内所有类的所有方法上
excution(* com.aop.*.add(..)) 切入aop包内所有类的add方法上
excution(* com.aop.*.add*(..)) 切入aop包内所有类的以add开头的方法上
9.2 注解实现AOP
package com.Aop;
/**
* 目标对象
**/
@Component
public class User {
public int add(){
return 1;
}
public int add(int i){
return i+1;
}
public int add(int i,String value){
System.out.println(value);
return i+1;
}
}
package com.Aop;
/**
* 切面
* */
@Aspect
@Component
public class Advices {
//定义公共切点
@Pointcut("execution(* com.Aop.User.add(int ,String))")
private void addPointCut(){}
//前置通知
@Before("execution(* com.Aop.User.add(int ,String))")
public static void addBefore(JoinPoint joinPoint){
//获取切入点的实参
Object[] args = joinPoint.getArgs();
System.out.println("日志开始");
}
//最终通知,是否异常都会执行
@After("execution(* com.Aop.User.add(int ,String))")
public static void addAfter(JoinPoint joinPoint){
//获取切入点的实参
Object[] args = joinPoint.getArgs();
System.out.println("日志结束");
}
//返回通知(可以拿到切入点的返回值),异常则不会执行
@AfterReturning(value = "execution(* com.Aop.User.add(int ,String))",returning = "res")
public static void addAfterRetrunning(JoinPoint joinPoint,Object res){
//获取切入点的实参
Object[] args = joinPoint.getArgs();
System.out.println("日志结束");
}
//异常通知
@AfterThrowing(value = "execution(* com.Aop.User.add(int ,String))",throwing = "e")
public static void addExecept(Exception e){
System.out.println("日志结束");
}
//环绕通知,此处引入了公共切点
@Around("addPointCut()")
public static void addAround(ProceedingJoinPoint proceedingJoinPoint){
System.out.println("日志开始");
try {
//控制切入点执行
proceedingJoinPoint.proceed();
} catch (Throwable e) {
throw new RuntimeException(e);
}
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">
<context:component-scan base-package="com"></context:component-scan>
<aop:aspectj-autoproxy/>
</beans>