使用Spring可使用简单的JavaBean实现之前EJB实现的功能, Spring是一个IOC和AOP容器框架java
public class HelloWorld {
private String name;
public void setName(String name) {
this.name = name;
}
public void hello() {
System.out.println("hello: " + name);
}
}
public class Main {
public static void main(String[] args) {
// 建立HelloWorld 的一个对象
HelloWorld helloWorld = new HelloWorld();
// 为 name 属性赋值
helloWorld.setName("kong");
// 调用hello 方法
helloWorld.hello();
}
}
复制代码
一个简单的helloWorld程序,其中第一步建立对象 和 第二步为属性赋值能够交给Spring框架来完成spring
// 1. 建立Spring IOC 容器对象,容器对象会调用构造器并调用HelloWorld类中的setName方法
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
// 2. 从IOC容器中获取Bean实例
HelloWorld helloWorld = (HelloWorld) ctx.getBean("helloWorld");
// 3. 调用 hello 方法
helloWorld.hello();
复制代码
<bean id="helloWorld" class="com.atguigu.spring.beans.HelloWorld">
<property name="name" value="Spring"></property>
</bean>
复制代码
IOC是翻转资源获取的方向, 传统资源查找方式是组件向容器发起请求查找资源, 容器适时的返回资源, 应用了IOC以后,是容器主动将资源推送给它所管理的组件,组件要作的是选择合适的方式来接收资源编程
DI: 组件以一些预先定义好的方式接受来自容器的资源注入设计模式
// 传统方式
A a = getA();
B b = getB();
b.setA(a)
复制代码
// 使用IOC实现
B b = getB();
复制代码
##Spring配置Bean Spring属性配置细节 如何配置Beanbash
配置方式: 基于XML文件的格式app
<bean id="helloWorld" class="com.atguigu.spring.beans.HelloWorld">
<property name="name" value="Spring"></property>
</bean>
class: 用于建立 bean的全类名,经过反射方式在IOC中建立bean, 要求bean中必需要有无参数的构造器
id: 用于获取容器中的bean,id值惟一
复制代码
Bean的配置方式: 经过全类名(反射)/经过工厂方法(静态工厂方法 & 实例工厂方法)、FactoryBean框架
IOC容器BeanFactory & ApplicationContext概述ide
依赖注入的方式:ui
<constructor-arg>
元素里声明属性,没有name属性index
type
来指定参数的位置和参数的类型以区分重载的构造器// 使用value属性值类配置
<constructor-arg value="Audi" index="2"></constructor-arg>
// 使用value子节点来配置
<constructor-arg type="int">
<value>250</value>
</constructor-arg>
复制代码
字面值: 能够用字符串表示的值,能够经过元素标签或value属性进行注入,基本数据类型及其封装类、String等类型均可以采用字面值注入的方式this
使用property的ref属性创建bean之间的引用关系
使用集合的基本标签进行集合的配置,例如list
,array
,``
配置Properties属性值
配置独立的集合bean,以供多个bean进行引用,使用util
命名空间
<util:list id="cars">
<ref bean="car"/>
<ref bean="car2"/>
</util:list>
复制代码
使用p
命名空间来为bean的属性赋值 <bean id="person" class="com.atguigu.spring.beans.Person" p:age="30" p:name="Queen" p:cars-ref='cars'></bean>
什么是自动装配: 在<bean>
的autowire属性里制定自动装配的模式
在Person类当中定义了setter setter里面有名字的信息,
自动装配的缺点:
继承关系: 配置上的继承关系 bean配置的重用 使用<parent>
关键字
依赖关系: 某些bean要在前面建立 depends-on
关键字 好比要求在配置Person时,必需要有一个关联的car! 换句话说person这个bean依赖于Car这个bean
使用scope
来设定做用域 默认状况下是单例模式,相同类型的bean都是一样的 prototype: 原型 容器初始化时不建立bean实例,而在每次请求时都建立一个新的Bean实例,并返回
好比须要用到系统部署的细节信息(好比文件路径),这些信息须要和Spring文件分离
使用PropertyPlaceholderConfigurer的BeanFactory 后置处理器,该处理器容许用户将Bean配置的部份内容外移动到属性文件中,能够在Bean配置文件中使用 ${var}
变量来从外部属性文件中加载属性,并使用这些属性来替换变量
可使用SpEL语句进行扩展性的操做:
Spring容许在Bean声明周期的特定点执行定制的任务 SpringIOC 容器对Bean的声明周期进行管理的过程:
在Bean的声明中设置init-method
和destroy-method
属性,为Bean指定 初始化和销毁方法
在类里面先将init方法(名字能够自定义,保证对应就行)定义好,
<bean id="car" class="..." init-method="init" destroy-method="destroy">
复制代码
ctx.close()
: 关闭IOC容器
建立Bean后置处理器 Bean后置处理器容许在调用初始化方法先后对Bean进行额外的处理
静态工厂方法: 直接调用某一个类的静态方法就能够返回Bean的实例
class
: 指向静态工厂方法的全类名factory-method
关键字: 指向静态工厂方法的名字constructor-arg
: 若是工厂方法须要传入参数,则使用constructor-arg来配置参数<bean id="car1" class="..." factory-method="getCar">
<constructor-arg value="audi"></constructor-arg>
</bean>
复制代码
实例工厂方法:: 先要建立工厂自己,再经过调用工厂
factory-bean
: 指向实例工厂方法的beanfactory-method
关键字定义工厂bean的方法<bean id="carFactory" class="..."></bean>
<bean id="car2" factory-bean="" factory-method="..">
复制代码
FactoryBean 是Spring提供的一个接口
class
: 指向FactoryBean的全雷鸣property
: 配置FactoryBean的属性 实际返回的实例是FactoryBean的getObject() 返回的实例 便于有时候配置Bean的时候用到Spring当中的其它Bean在classpath中扫描组件
@Component
: 基本注解,标识一个Spring管理的组件@Respository
: 标识持久层组件@Service
: 标识服务层(业务层)@Controller
: 表现层组件 Spring默认命名策略: 使用非限定类名时,第一个字母小写, 也能够在注解中经过value属性值标识组件的名称须要在Spring配置文件中声明<context:component-scan>
来限定扫描哪些包
指定一个须要扫描的基类包,Spring容器会扫描基类包以及其子包中的全部类,多个包能够经过逗号分隔 context:exclude-filter
: 排除指定组件 context:include-filter
: 包含表达式组件
一个计算器接口,
须要完成两个额外的需求, 生成日志 + 进行验证
日志代码差很少 核心代码混乱,愈来愈多非业务需求,每一个方法在处理 还要兼顾其余多个关注点
代码分散: 只是为了知足一个单一需求,不得不在多个模块(方法)里屡次重复相同的日志代码,若是日志需求发生变化,必须修改全部模块.
AOP方式解决
动态代理解决 代理设计模式: 使用一个代理将对象包装起来,而后用该代理对象取代原始对象,任何对原始对象的调用都要经过代理
public class ArithmeticCalculatorLoggingProxy {
//要代理的对象
private ArithmeticCalculator target;
public ArithmeticCalculator getLoggingProxy() {
ArithmeticCalculator proxy = null;
// 代理对象由哪个类加载器负责加载
ClassLoader loader = target.getClass().getClassLoader();
// 代理对象的类型,即其中有哪些方法
Class[] interfaces = new Class[]{ArithmeticCalculator.class};
// 当调用代理对象其中的方法时,须要执行的代码
InvocationHandler h = new InvocationHandler() {
/** * @param: proxy: 正在返回的代理对象,通常状况下,invoke方法中不使用 * @param: method: 正在被调用的方法 * @args: 调用方法时,传入的参数 */
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("invoke...");
return 0;
}
};
proxy = (ArithmeticCalculator) Proxy.newProxyInstance(loader, interfaces, h);
return proxy;
}
}
复制代码
动态是什么意思?体如今哪里?
横切关注点方法 在应用AOP时,须要定义公共功能,但能够明肯定义功能在哪里,以何种方式应用,而且没必要修改受影响的类.
AOP的好处:
计算器加减乘除的例子:
切面: 通知: 切面中的每个方法就是通知 链接点: 程序执行的某个特定位置 一个具体的存在 切点: 看不见 经过切点定位到特定链接点
在配置文件中加入AOP的命名空间 xmlns:aop="..."
基于注解的方式: 在配置文件中加入以下配置: 把横切关注点的代码抽象到切面的类中 切面首先是一个Java bean,须要加入@Component
注解 使用@Aspect
注解标注出切面,
@Before
: 方法执行前@After
: 方法执行后@AfterReturning
: 通知方法在目标方法返回后调用@AfterThrowing
: 通知方法在目标方法抛出异常后调用@Around
: 环绕execution() *
能够表示任意修饰符及任意返回值
使用@Order
指定切面的优先级,值越小,优先级越高
从新用execution 那一坨东西 定义一个方法,用于声明切入点表达式, 以后再用到该切点的地方就直接调用该方法便可声明对应切点
@Pointcut("...")
public void declareJointPointExpression(){}
复制代码
<aop:config>
<aop:aspect ref="audience">
<aop:before
pointcut="..." method="方法名"/>
<aop: after-returnning
pointcut="execution(...)"/>
</aop:aspect>
</aop:config>
复制代码
必须为不一样的方法重写相似的样板代码,存在大量的重复部分
public void purchase(String isbn, String username) {
Connection conn = null;
try {
conn = dataSource.getConnection();
conn.setAutoCommit(false);
...
conn.commit();
} catch (SQLException e) {
e.printStackTrace();
if (conn != null) {
try {
conn.rollback();
} catch (SQLException e) {
e.printStackTrace();
}
}
throw new RuntimeException(e);
} finally {
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
复制代码
编程式 声明式
Spring
配置事务管理器 启用事务注解 @Transactional