1.创建一个maven项目,在pom.xml中导入spring的坐标
<?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>org.example</groupId>
<artifactId>SpringDemo2</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.15.RELEASE</version>
</dependency>
</dependencies>
</project>
2.创建UserDao接口和UserDao接口的实现类UserDaoImpl 3.创建spring的xml配置文件,然后在其中给实现类标注id
<bean id="userDao" class="com.impl.UserDaoImpl"></bean>
public class testDemo {
public static void main(String[] args) {
ApplicationContext app=new ClassPathXmlApplicationContext("applicationContext.xml");
UserDao userDao = (UserDao) app.getBean("userDao");
userDao.say();
}
}
默认是singleton
<bean id="userDao" class="com.impl.UserDaoImpl"></bean>
ApplicationContext app=new ClassPathXmlApplicationContext("applicationContext.xml");
UserDao userDao = (UserDao) app.getBean("userDao");
UserDao userDao1=(UserDao)app.getBean("userDao");
System.out.println(userDao);
System.out.println(userDao1);
默认单例模式
ApplicationContext app=new ClassPathXmlApplicationContext("applicationContext.xml");
意思是加载配置文件,创建Spring容器
1.在或内部通过定义的, 2.该bean不管是否指定id或者name,该bean都有一个唯一的匿名标识符,且不能被指定别名 3.该bean队其他外部的bean不可见。
Util名称空间创建的集合有id,可以给其他bean引用,在使用前需要引入名称空间: xmlns:util=“http://www.springframework.org/schema/util”
<?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:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd">
<!-- 相当于new LinkedHashMap() -->
<util:map id="myMap">
<entry key="key01" value="value01"></entry>
</util:map>
<bean id="person" class="com.atguigu.bean.Person">
<!-- 引用myMap ->
<property name="map" ref="myMap"></property>
</bean>
</beans>
通过属性(a)选择属性(a)的属性(b)
<bean id="car01" class="com.atguigu.bean.Car">
<property name="carName" value="宝马"></property>
</bean>
<!-- 级联属性:属性的属性 -->
<bean id="person01" class="com.atguigu.bean.Person">
<!-- 为car赋值的时候改变car的属性 -->
<property name="car" ref="car01"></property>
<!-- 给car属性的carName属性赋值 -->
<property name="car.carName" value="奔驰"></property>
</bean>
在bean定义中含了大量的配置信息,其中包括容器相关的信息(比如初始化方法、静态工厂方法名等等)以及构造器参数和属性值。子bean定义就是从父bean定义继承配置数据的bean定义。它可以覆盖父bean的一些值,或者添加一些它需要的值。使用父/子bean定义的形式可以节省很多的输入工作。实际上,这就是一种模板形式。
class全类名也会继承,但是只是继承配置信息,而不是父子关系
全类名省略不写的前提时,当前bean对象的类型与继承的bean类型一致
如果需要对继承的数据进行修改,就自行对相关属性再赋值,完成值的覆盖
<bean id="parent" class="com.timo.domain.Parent">
<property name="name" value="ouyangfeng"/>
</bean>
<!--下面的parent表示这个child的bean的父亲是id=parent的这个类-->
<bean id="child" class="com.timo.domain.Child" parent="parent">
<property name="age" value="18"/>
</bean>
下面说的就是: 抽象bean不必映射到任何类,即不用写全类名
getBean(people.class);//类型查找
getBean("people01");//ID查找
getBean("people01",people.class);//ID加类型查找
<bean id="userDao" class="com.impl.UserDaoImpl" scope="singleton"></bean>
<bean id="userDao" class="com.impl.UserDaoImpl" scope="prototype"></bean>
多例模式每一次获取的对象都不相同
UserDaoImpl类:
package com.impl;
import com.UserDao;
public class UserDaoImpl implements UserDao {
@Override
public void say() {
System.out.println("用户登录");
}
void init()
{
System.out.println("初始化中...");
}
void destory()
{
System.out.println("被销毁中....");
}
}
配置文件:
<bean id="userDao" class="com.impl.UserDaoImpl" init-method="init" destroy-method="destory" ></bean>
测试类:
public class testDemo {
public static void main(String[] args) {
ApplicationContext app=new ClassPathXmlApplicationContext("applicationContext.xml");
UserDao userDao = (UserDao) app.getBean("userDao");
System.out.println(userDao);
//需要强转成其子类,才能调用close方法,来关闭容器
((ClassPathXmlApplicationContext)app).close();
}
}
容器没有关闭,所以对象没有被释放,也就不会去调用销毁方法
//1.编写后置处理器的实现类
//2.将后置处理器注册在配置文件中
public class MyBeansProcess implements BeanPostProcessor {
//初始化之前调用
//Object bean: 将要初始化的bean
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println(beanName+"Bean将要调用初始化方法"+" "+bean);
return bean;//返回传入的bean
}
//String beanName: bean在xml中配置的id
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println(beanName+"Bean初始化方法调用完毕"+" "+bean);
//初始化之后返回的是什么,容器中保存的就是什么
return bean;
}
}
配置文件:
<bean id="book" class="com.dhy.Factory.book"/>
<bean id="beanPostProcess" class="com.dhy.Factory.MyBeansProcess"/>
book类;
public class book {
book()
{
System.out.println("book的初始化方法");
}
@Override
public String toString() {
return "图书";
}
}
测试类:
public class main {
public static void main(String[] args) {
ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext("factory.xml");
System.out.println(app.getBean("book"));
if(app.getBean("book")!=null)
System.out.println("NO");
else
System.out.println("YES");
}
}
工厂类:
public class sf {
public static UserDao getUserDao()
{
return new UserDaoImpl();
}
}
配置文件:
当添加了factory-method属性后,就会去找当前全类名对应下面的getUserDao方法,返回对应的对象
<bean id="userDao" class="com.fac.staticFac.sf" factory-method="getUserDao"></bean>
测试类:
public class testDemo {
public static void main(String[] args) {
ApplicationContext app=new ClassPathXmlApplicationContext("applicationContext.xml");
UserDao userDao = (UserDao) app.getBean("userDao");
System.out.println(userDao);
//需要强转成其子类,才能调用close方法,来关闭容器
((ClassPathXmlApplicationContext)app).close();
}
}
工厂类:
public class sf {
public UserDao getUserDao()
{
return new UserDaoImpl();
}
}
配置文件:
在查找到userDao的ID时,会去查查找ID为f的bean标签,然后创建工厂对象,然后调用其方法,返回一个userDao对象
<bean id="f" class="com.fac.staticFac.sf" ></bean>
<bean id="userDao" factory-bean="f" factory-method="getUserDao"></bean>
测试类代码不变,:
public class testDemo {
public static void main(String[] args) {
ApplicationContext app=new ClassPathXmlApplicationContext("applicationContext.xml");
UserDao userDao = (UserDao) app.getBean("userDao");
System.out.println(userDao);
//需要强转成其子类,才能调用close方法,来关闭容器
((ClassPathXmlApplicationContext)app).close();
}
}
实现了接口的工厂类:
/*
* 1.编写一个FactoryBean的实现类
* 2.在Spring配置文件中进行注册
* */
public class factory implements FactoryBean {
/*工厂方法,返回创建的对象
* */
public Object getObject() throws Exception {
Book b=new Book();
return b;
}
/*返回创建的对象的类型,Spring会自动调用这个方法来确认创建的对象是什么类型
* */
public Class<?> getObjectType() {
return Book.class;
}
//是单例吗 true:是单例 false:不是单例
public boolean isSingleton() {
return false;
}
}
配置文件:
<bean id="myFacBeanImple" class="com.dhy.Factory.factory"/>
测试类:
public class main {
public static void main(String[] args) {
ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext("factory.xml");
//返回的对象是工厂方法里面返回的对象
System.out.println(app.getBean("myFacBeanImple"));
}
}
UserService类中需要用到User类对象,因此需要将User类注入到UserService类中,下面演示:
配置文件:
<bean id="userDao" class="com.User.User"></bean>
<!--property标签写在被注入的类标签内部,即要设置谁的属性,就写在谁的bean标签内部-->
<bean id="userService" class="com.User.UserService">
<!--通过属性注入,这里name填入的是截取set方法后set部分后,剩余部分变小写的值,即属性的名字-->
<!--ref是要注入哪个类,这里注入的是userDao的ID表示的User类-->
<property name="user" ref="userDao"></property>
</bean>
userService类:
public class UserService {
private User user;
public void setUser(User user) {
this.user = user;
}
public void show()
{
//在容器内部,将user对象注入UserService,即通过UserService的set方法,给US的成员变量user赋值
user.show();
}
}
user类:
public class User {
public void show()
{
System.out.println("大忽悠来了");
}
}
测试类:
public class testDemo {
public static void main(String[] args) {
ApplicationContext app=new ClassPathXmlApplicationContext("applicationContext.xml");
UserService us=(UserService)app.getBean("userService");
us.show();
}
}
注意:只有从容器内部拿出来的UserService才通过US类的setUser方法,完成了对user对象的赋值,即注入,直接new一个,没有用,因此其没有被注入user对象,会报空指针异常
第一步: 引入p命名空间
xmlns:p="http://www.springframework.org/schema/p"
第二步: 修改注入方式
注意: userDao-ref是用来注入对象的,而userDao是用来注入普通属性的
<bean id="userDao" class="com.User.User"></bean>
<bean id="userService" class="com.User.UserService"
p:user-ref="userDao">
</bean>
userService类:
public class UserService {
private User user;
public UserService(User user) {
this.user = user;
}
public UserService() {
}
public void show()
{
//在容器内部,将user对象注入UserService,即通过UserService的set方法,给US的成员变量user赋值
user.show();
}
}
配置文件:
<bean id="userDao" class="com.User.User"></bean>
<bean id="userService" class="com.User.UserService">
<constructor-arg name="user" ref="userDao"></constructor-arg>
</bean>
测试类:
public class testDemo {
public static void main(String[] args) {
ApplicationContext app=new ClassPathXmlApplicationContext("applicationContext.xml");
UserService us=(UserService)app.getBean("userService");
us.show();
}
}
给User的name和age属性注入两个值
package com.User;
public class User
{
private String name;
private int age;
public void show()
{
System.out.println("姓名: "+name+" 年龄: "+age);
}
public void setName(String name) {
this.name=name;
}
public void setAge(int age) {
this.age=age;
}
}
配置文件:
//这里是通过setName<---Name<---name来找到对应的set方法,进行属性的设置
<bean id="userDao" class="com.User.User">
<property name="name" value="大忽悠"/>
<property name="age" value="18" />
</bean>
测试:
public class testDemo {
public static void main(String[] args) {
ApplicationContext app=new ClassPathXmlApplicationContext("applicationContext.xml");
User us=(User)app.getBean("user");
us.show();
}
}
ref是引用,被引用的内容,必须已经存在于Spring容器中
被注入的类:
public class UserService {
private List<String> list;
private Map<String,User> map;
private Properties properties;
public void setList(List<String> list) {
this.list = list;
}
public void setMap(Map<String, User> map) {
this.map = map;
}
public void setProperties(Properties properties) {
this.properties = properties;
}
void show()
{
System.out.println(list);
System.out.println(map);
System.out.println(properties);
}
}
map中的user对象
public class User
{
private String name;
private int age;
public void setName(String name) {
this.name=name;
}
public void setAge(int age) {
this.age=age;
}
}
配置文件:
<bean id="user" class="com.User.UserService">
<property name="list" >
<list>
<!--普通类型,不是引用类型,用value-->
<value>大忽悠</value>
<value>和</value>
<value>小朋友</value>
</list>
</property>
<property name="map">
<map>
<entry key="用户:" value-ref="user1" ></entry>
<entry key="用户:" value-ref="user2" ></entry>
</map>
</property>
<property name="properties">
<props>
<prop key="p1">ppp1</prop>
<prop key="p3">ppp2</prop>
<prop key="p2">ppp3</prop>
</props>
</property>
</bean>
<bean id="user1" class="com.User.User">
<!-- name-Name-setName-->
<property name="name" value="Tom"></property>
<property name="age" value="18"></property>
</bean>
<bean id="user2" class="com.User.User">
<!-- name-Name-setName-->
<property name="name" value="Booby"></property>
<property name="age" value="19"></property>
</bean>
测试类:
public class testDemo
{
public static void main(String[] args) {
ApplicationContext app=new ClassPathXmlApplicationContext("applicationContext.xml");
UserService us=(UserService) app.getBean("user");
us.show();
}
}
第二种传入一个字节码对象类型演示:
ApplicationContext app=new ClassPathXmlApplicationContext("applicationContext.xml");
UserService bean = app.getBean(UserService.class);
bean.show();
1.通过获取字节码文件对象,获取的返回值,不用进行强制类型转换
2.当出现多个类型相同的bean(对象)时,只能使用第一种方式
手动创建c3p0数据源
/*手动创建c3p0数据源*/
@Test
public void test1() throws PropertyVetoException, SQLException {
ComboPooledDataSource dataSource=new ComboPooledDataSource();
dataSource.setDriverClass("com.mysql.jdbc.Driver");
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test");
dataSource.setUser("root");
dataSource.setPassword("126433");
Connection connection = dataSource.getConnection();
System.out.println(connection);
connection.close();
}
手动创建druid数据源
/*手动创建druid数据源*/
@Test
public void test2() throws PropertyVetoException, SQLException {
DruidDataSource druidDataSource = new DruidDataSource();
druidDataSource.setDriverClassName("com.mysql.jdbc.Driver");
druidDataSource.setUrl("jdbc:mysql://localhost:3306/test");
druidDataSource.setUsername("root");
druidDataSource.setPassword("126433");
DruidPooledConnection connection = druidDataSource.getConnection();
System.out.println(connection);
connection.close();
}
jdbc.properties配置文件:
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/test1
jdbc.username=root
jdbc.password=126433
演示:
/*手动创建c3p0数据源(加载配置文件形式)*/
@Test
public void test1() throws PropertyVetoException, SQLException {
//读取配置文件
//参数: 基名,相对于类加载路径地址---resource文件下面的地址
//不需要扩展名
ResourceBundle rb=ResourceBundle.getBundle("jdbc");
String driver=rb.getString("jdbc.driver");
String url=rb.getString("jdbc.url");
String username=rb.getString("jdbc.username");
String password=rb.getString("jdbc.password");
//创建数据源对象,设置连接参数
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setDriverClass(driver);
dataSource.setJdbcUrl(url);
dataSource.setUser(username);
dataSource.setPassword(password);
Connection connection=dataSource.getConnection();
System.out.println(connection);
connection.close();
}
可以将DataSource的创建权交给Spring容器去完成
第一步: 导入坐标
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.15.RELEASE</version>
</dependency>
第二步: 配置文件中完成注入
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test1"></property>
<property name="user" value="root"></property>
<property name="password" value="126433"></property>
</bean>
第三步: 测试
ApplicationContext app=new ClassPathXmlApplicationContext("applicationContext.xml");
DataSource bean = app.getBean(DataSource.class);
Connection connection=bean.getConnection();
System.out.println(connection);
connection.close();
第一步: 引入命名空间和约束路径
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
<!--上面一行copy一份,前面加个context前缀,把后面的beans改成context-->
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util https://www.springframework.org/schema/util/spring-util.xsd
<!--上面一行copy一份,把后面的beans都改成context-->
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
第二步: 加载配置文件
<!--加载外部的properties文件-->
<!--当前要加载的properties文件在资源文件下,前面需要加上classpath:-->
<context:property-placeholder location="classpath:jdbc.properties"/>
第三步: 完成对数据库连接池对象的相关信息注入
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<!--通过键值的方式引入值-->
<property name="driverClass" value="${jdbc.driver}"></property>
<property name="jdbcUrl" value="${jdbc.url}"></property>
<property name="user" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
jdbc.properties配置文件:
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/test1
jdbc.username=root
jdbc.password=126433
第四步:测试
ApplicationContext app=new ClassPathXmlApplicationContext("applicationContext.xml");
DataSource bean = app.getBean(DataSource.class);
Connection connection=bean.getConnection();
System.out.println(connection);
connection.close();
环境准备:
需要注入的类:
//<bean id="userDao" class="com.User.User"></bean>
@Component("userDao")
public class User
{
public void show()
{
System.out.println("User注入完成");
}
}
被注入的类:
//<bean id="user" class="com.User.UserService">
@Component("user")
public class UserService {
// <property name="user" ref="userDao"></property>
@Autowired
@Qualifier("userDao")
private User user;
public void setUser(User user) {
this.user = user;
}
public void show()
{
user.show();
}
}
组件扫描配置:
<!--配置组件扫描-->
<context:component-scan base-package="com"/>
测试:
ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService bean = app.getBean(UserService.class);
bean.show();
如果是xml方式配置,那么在进行对象注入的时候,被注入的类,需要提供相关成员变量的set方法
如果是注解配置,我们把注解放到属性,即成员变量上面后,注解会直接通过反射给成员变量赋值,这样就不需要set方法了
如果按照类型注入,只需要写Autowired,前提是对应的数据类型在容器中的对象只有一个 如果按照id注入,那么还需要在上面加上Autowired注解
@Component("user")
public class UserService {
@Autowired//按照数据类型从Spring容器中进行匹配,如果数据类型的对象只有一个
//下面的qualifier可以省略不写,如果存在多个相同数据类型的对象,则会产生二义性
@Qualifier("userDao")//按照id的名称,从容器中进行匹配的
private User user;
public void show()
{
user.show();
}
}
如果资源类型的bean不止一个,默认根据@Autowired注解标记的成员变量名作为id查找bean,进行装配
@Qualifier:指定一个名作为id,让spring别使用变量名作为id
使用@Autowired注解完成属性依赖注入时,写在属性上与写在set方法上的区别 @Autowired注解详解——超详细易懂
resource相当于Autowired加上Qualifier
@Component("user")
public class UserService {
@Resource(name="userDao")
private User user;
public void show()
{
user.show();
}
}
简单使用演示:
@Component("user")
public class UserService {
@Value("18")
private int age;
@Resource(name="userDao")
private User user;
public void show()
{
System.out.println("年龄为:"+age);
}
}
@Component("user")
public class UserService {
@Value("${jdbc.driver}")
private String driver;
@Resource(name="userDao")
private User user;
public void show()
{
System.out.println(driver);
}
}
<!--配置组件扫描-->
<context:component-scan base-package="com"/>
<!--加载外部的properties文件-->
<!--当前要加载的properties文件在资源文件下,前面需要加上classpath:-->
<context:property-placeholder location="classpath:jdbc.properties"/>
一个类上面只能添加一个scope注解
//一个类上面只能添加一个scope注解
//@Scope("prototype")
@Scope("singleton")
public class testDemo {
public static void main(String[] args) {
ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService bean = app.getBean(UserService.class);
bean.show();
}
}
@Component("user")
public class UserService
{
public UserService() {
System.out.println("构造方法执行中...");
}
@PostConstruct
void init()
{
System.out.println("初始化中...");
}
@PreDestroy
void destory()
{
System.out.println("销毁中....");
}
public void show()
{
System.out.println("show方法调用");
}
}
容器没有关闭,所以对象没有被释放,也就不会去调用销毁方法,因此只有在调用了close方法,容器被关闭后,对象才会被释放,才会去调用销毁方法
测试类:
public class testDemo {
public static void main(String[] args) {
ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService bean = app.getBean(UserService.class);
bean.show();
app.close();
}
}
//标志该类是Spring的核心配置类
@Configuration
//<context:component-scan base-package="com"/>
//相当于配置组件扫描
@ComponentScan("com")
//<import resource=""/> 通过import将数据域相关的配置加载到核心(总)配置中
@Import(DataSourceCofiguration.class)
//如果要加载多个配置
//@Import({DataSourceCofiguration.class,...})
public class SpringCofiguration {}
//<context:property-placeholder location="classpath:jdbc.properties"/>
//加载配置文件进Spring容器
@PropertySource("classpath:jdbc.properties")
public class DataSourceCofiguration {
@Value("${jdbc.driver}")
private String driver;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String pasword;
@Bean("dataSource") //Spring会将当前方法的返回值以指定名称存储到Spring容器中
public DataSource getDataSource() throws PropertyVetoException, SQLException {
ComboPooledDataSource dataSource=new ComboPooledDataSource();
dataSource.setDriverClass(driver);
dataSource.setJdbcUrl(url);
dataSource.setUser(username);
dataSource.setPassword(pasword);
Connection connection = dataSource.getConnection();
System.out.println("执行getDataSource方法,返回connection:"+connection);
connection.close();
return dataSource;
}
}
public class test {
public static void main(String[] args) throws SQLException {
ApplicationContext app= new AnnotationConfigApplicationContext(SpringCofiguration.class);
app.getBean(UserService.class).show();
}
}
第一步: 在pom.xml中导入Spring-test的坐标
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.0.5.RELEASE</version>
</dependency>
第二步: 创建测试类
@RunWith(SpringJUnit4ClassRunner.class)//让测试运行于Spring测试环境
//通过读取配置文件,在测试类中完成对Bean的注入
//@ContextConfiguration("classpath:applicationContext.xml")
//通过加载核心配置类,完成注入操作
@ContextConfiguration(classes = SpringCofiguration.class)//如果要加载多个,使用数组形式
public class JunitTest
{
@Autowired
private UserService us;
@Autowired
private DataSource ds;
@Test
public void test() throws SQLException {
us.show();
System.out.println(ds.getConnection());
}
}
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
第二步: 完善web目录结构
第三步: xml文件配置(也可以使用注解配置)
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<servlet>
<servlet-name>UserServlet</servlet-name>
<servlet-class>Web.UserServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>UserServlet</servlet-name>
<url-pattern>/userServlet</url-pattern>
</servlet-mapping>
</web-app>
第四步: 通过xml配置,在容器中创建单例的userservice对象
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util https://www.springframework.org/schema/util/spring-util.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<bean id="userService" class="com.User.UserService"></bean>
</beans>
userServlet类进行测试:
public class UserServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
ApplicationContext app=new ClassPathXmlApplicationContext("applicationContext.xml");
UserService bean = app.getBean(UserService.class);
bean.show();
}
}
tomcat服务器别忘记部署
要解决的问题:
解决方法:
代码:
监听器类:
public class LS implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
ApplicationContext app=new ClassPathXmlApplicationContext("applicationContext.xml");
//将Spring的应用上下文对象存储到ServletContext域中
ServletContext servletContext = servletContextEvent.getServletContext();
servletContext.setAttribute("app",app);
System.out.println("Spring容器创建完毕");
}
@Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
}
}
web.xml中配置监听器
<!--配置监听器-->
<listener>
<listener-class>Listener.LS</listener-class>
</listener>
userServlet类中通过从ServletContext域中拿到存放数据,来取出上下文对象,从而从Spring容器中拿出单例对象US
public class UserServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
ServletContext servletContext = this.getServletContext();
ApplicationContext app = (ApplicationContext)servletContext.getAttribute("app");
UserService bean = app.getBean(UserService.class);
bean.show();
}
}
ApplicationContext app=new ClassPathXmlApplicationContext("applicationContext.xml");
web.xml配置文件:
<!--全局初始化参数-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>applicationContext.xml</param-value>
</context-param>
监听器类:
@Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
ServletContext servletContext = servletContextEvent.getServletContext();
//读取web.xml中的全局参数
String contextConfigLocation = servletContext.getInitParameter("contextConfigLocation");
ApplicationContext app=new ClassPathXmlApplicationContext(contextConfigLocation);
//将Spring的应用上下文对象存储到ServletContext域中
servletContext.setAttribute("app",app);
System.out.println("Spring容器创建完毕");
}
WebAppUtils工具类:
public class WebAppUtils {
static public ApplicationContext getApp(ServletContext sc)
{
return (ApplicationContext)sc.getAttribute("app");
}
}
UserServlet类:
public class UserServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
ServletContext servletContext = this.getServletContext();
ApplicationContext app = WebAppUtils.getApp(servletContext);
UserService bean = app.getBean(UserService.class);
bean.show();
}
}
Spring-web坐标:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.2.9.RELEASE</version>
</dependency>
web.xml配置:
<!--全局初始化参数-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<!--配置监听器-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
UserServlet类:
public class UserServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
ServletContext servletContext = getServletContext();
ApplicationContext app = WebApplicationContextUtils.getWebApplicationContext(servletContext);
UserService bean = app.getBean(UserService.class);
bean.show();
}
}
TargetInterface接口:
public interface TargetInterface {
void show();
}
target类:
public class Target implements TargetInterface {
@Override
public void show() {
System.out.println("show方法调用");
}
}
advice增强类:
public class Advice {
void berfore()
{
System.out.println("前置增强");
}
void after()
{
System.out.println("后置增强");
}
}
main测试类:
public class main {
public static void main(String[] args) {
//目标对象
Target target=new Target();
//增强对象
Advice advice=new Advice();
Object p = Proxy.newProxyInstance(
//目标对象类加载器
target.getClass().getClassLoader(),
//目标对象相同的接口字节码对象数组
target.getClass().getInterfaces(),
//目标方法执行器,帮我们目标对象执行目标方法
new InvocationHandler() {
//调用代理对象的任何方法,实际都是执行invoke方法
@Override
//proxy: 给jdk使用的,任何时候都不要动这个对象
//method:当前要执行的目标对象的方法
//args:这个方法调用时外界传入的参数
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
advice.berfore();//前置增强
//利用反射执行目标方法
//目标方法执行后的返回值
Object invoke = method.invoke(target, args);
advice.after();//后置增强
//返回值必须真正返回出去,外界才能拿到执行后的返回值
return invoke;
}
}
);
//调用代理对象的方法
((TargetInterface)p).show();
}
}
Spring五版本,已经将cglib相关jar包放入core的核心包里面了
target类:
public class Target {
public void show() {
System.out.println("show方法调用");
}
}
advice增强类:
public class Advice {
void berfore()
{
System.out.println("前置增强");
}
void after()
{
System.out.println("后置增强");
}
}
main测试主类:
public class main {
public static void main(String[] args) {
//目标对象
Target target=new Target();
//增强对象
Advice advice=new Advice();
//返回值就是动态代理生成的对象,基于cglib
//1,创建增强器
Enhancer enhancer=new Enhancer();
//2.设置父类(目标对象)
enhancer.setSuperclass(Target.class);
//3.设置回调
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object proxy, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
//前置增强
advice.berfore();
//执行目标
Object invoke = method.invoke(target, args);
//后置增强
advice.after();
return invoke;
}
});
//4.创建代理对象
Target proxy = (Target) enhancer.create();
proxy.show();
}
}
<!--导入aspectj的坐标-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.4</version>
</dependency>
public interface TargetInterface {
void show();
}
public class Target implements TargetInterface{
public void show() {
System.out.println("Target's show");
}
}
public class MyAspect {
public void before()
{
System.out.println("前置增强");
}
}
<!--配置目标对象-->
<bean id="target" class="com.dhy.aop.Target"></bean>
<!--配置切面-->
<bean id="myAspect" class="com.dhy.aop.MyAspect"></bean>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop"
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
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--配置目标对象-->
<bean id="target" class="com.dhy.aop.Target"></bean>
<!--配置切面-->
<bean id="myAspect" class="com.dhy.aop.MyAspect"></bean>
<!--配置织入:在配置文件中告诉Spring框架,那些方法(切点)需要进行哪些增强(前置,后置...)-->
<!--要引入AOP命名空间-->
<aop:config>
<!--声明切面-->
<aop:aspect ref="myAspect">
<!--切面=切点+通知-->
<aop:before method="before" pointcut="execution(public void com.dhy.aop.Target.show())"/>
</aop:aspect>
</aop:config>
</beans>
先导入spring-test的坐标:
<!--引入Spring测试坐标-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.0.5.RELEASE</version>
</dependency>
@RunWith(SpringJUnit4ClassRunner.class)
//在测试类的内部,完成Bean的注入
@ContextConfiguration("classpath:applicationContext.xml")
public class AopTest {
@Autowired
private TargetInterface target;
@Test
public void test()
{
target.show();
}
}
1.代表匹配一个或者多个字符: Math*r—>Math开头,r结尾的字符串都满足格式要求
2.匹配任意一个参数
3.只能匹配一层路径
<aop:config>
<!--声明切面-->
<aop:aspect ref="myAspect">
<!--切面=切点+通知-->
<!--cmo.dhy.aop报下的任意类的任意方法的任意参数,返回值任意的方法都会被增强-->
<aop:before method="before" pointcut="execution(* com.dhy.aop.*.*(..))"/>
</aop:aspect>
</aop:config>
切面类:
public class MyAspect {
public void before()
{
System.out.println("前置增强");
}
public void after()
{
System.out.println("后置增强");
}
//Proceeding JoinPoint: 正在执行的连接点--->切点
public Object around(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("环绕前");
//就是利用反射调用的目标方法,等同于method.invoke(obj,args)
Object proceed = pjp.proceed();//切点的方法
System.out.println("环绕后");
//反射调用的返回值也要返回回去,这个返回值就是方法的返回值
return proceed;
}
}
切面的配置:
<aop:config>
<!--声明切面-->
<aop:aspect ref="myAspect">
<!--切面=切点+通知-->
<aop:before method="before" pointcut="execution(* com.dhy.aop.*.*(..))"/>
<aop:after method="after" pointcut="execution(* com.dhy.aop.*.*(..))"/>
<aop:around method="around" pointcut="execution(* com.dhy.aop.*.*(..))"/>
</aop:aspect>
</aop:config>
结果:
目标类抛出异常:
public class Target implements TargetInterface{
public void show() {
System.out.println("Target's show");
int i=1/0;//制造数学异常
}
}
切面配置:
<aop:config>
<!--声明切面-->
<aop:aspect ref="myAspect">
<!--切面=切点+通知-->
<aop:around method="around" pointcut="execution(* com.dhy.aop.*.*(..))"/>
<aop:after-throwing method="throwing" pointcut="execution(* com.dhy.aop.*.*(..))"/>
</aop:aspect>
</aop:config>
增强方法:
public void throwing()
{
System.out.println("抛出异常");
}
增强方法:
public void after()
{
System.out.println("最终增强");
}
切面配置:
<aop:config>
<!--声明切面-->
<aop:aspect ref="myAspect">
<!--切面=切点+通知-->
<aop:around method="around" pointcut="execution(* com.dhy.aop.*.*(..))"/>
<aop:after-throwing method="throwing" pointcut="execution(* com.dhy.aop.*.*(..))"/>
<aop:after method="after" pointcut="execution(* com.dhy.aop.*.*(..))"/>
</aop:aspect>
</aop:config>
切面配置:
<aop:config>
<!--声明切面-->
<aop:aspect ref="myAspect">
<!--抽取切点表达式-->
<aop:pointcut id="myPointCut" expression="execution(* com.dhy.aop.*.*(..))"/>
<!--切面=切点+通知-->
<aop:around method="around" pointcut-ref="myPointCut"/>
<aop:after-throwing method="throwing" pointcut-ref="myPointCut"/>
<aop:after method="after" pointcut-ref="myPointCut"/>
</aop:aspect>
</aop:config>
配置文件:
<!--组件扫描-->
<!--使用时,加上context的命名空间-->
<context:component-scan base-package="com.dhy.anno"/>
<!--aop的自动代理-->
<!--使用时,加上aop的命名空间-->
<aop:aspectj-autoproxy/>
切面类:
@Component("MyAspect")
@Aspect //标注当前类是一个切面类
public class MyAspect {
//Proceeding JoinPoint: 正在执行的连接点--->切点
public Object around(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("环绕前");
Object proceed = pjp.proceed();//切点的方法
System.out.println("环绕后");
return proceed;
}
public void throwing() {
System.out.println("抛出异常");
}
//配置最终增强
@After("execution(* com.dhy.anno.*.*(..))")//参数是切点表达式
public void after()
{
System.out.println("最终增强");
}
}
目标类:
@Component("Target")
public class Target implements TargetInterface {
public void show() {
System.out.println("Target's show");
}
}
我们只需要为通知方法的参数列表上写上一个参数: JoinPoint joinpoint (封装了目标方法的详细信息)
returning=“result” :告诉spring,使用result变量来接收返回值
throwing=“exception”: 告诉spring,exception变量用来接收异常
如上面的returning和throwing方式,告诉spring我们填入的参数是什么
切面类:
@Component("MyAspect")
@Aspect //标注当前类是一个切面类
public class MyAspect {
@Around("point()")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("环绕前");
Object proceed = pjp.proceed();
System.out.println("环绕后");
return proceed;
}
@After("MyAspect.point()")
public void after()
{
System.out.println("最终增强");
}
//定义切点表达式
@Pointcut("execution(* com.dhy.anno.*.*(..))")
public void point(){};
}
注解方式是默认按照类名的字符串大小比较来决定执行顺序,如果时xml配置,则是由配置的先后顺序决定 可以使用@order(int i)注解,来改变切面的运行顺序,数值越小,优先级越高
<!--mysql驱动的坐标-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.32</version>
</dependency>
<!--c3p0数据库连接池的坐标-->
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
</dependency>
<!--druid数据库连接池坐标-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.10</version>
</dependency>
<!--spring jdbc的坐标-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.0.5.RELEASE</version>
</dependency>
<!--spring tx的坐标-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.0.5.RELEASE</version>
</dependency>
public class JdbcTemplteTest {
@Test
public void test1() throws PropertyVetoException {
//创建数据源对象
ComboPooledDataSource dataSource=new ComboPooledDataSource();
dataSource.setDriverClass("com.mysql.jdbc.Driver");
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test1");
dataSource.setUser("root");
dataSource.setPassword("126433");
JdbcTemplate jdbcTemplate = new JdbcTemplate();
//设置数据源对象 知道数据库在哪
jdbcTemplate.setDataSource(dataSource);
//执行操作
int row=jdbcTemplate.update("insert into account values (?,?)","大忽悠",8000);
System.out.println("影响的行数:"+row);
}
}
通过appOfDao.xml完成配置
将数据库连接池对象注入到jdbctemplate模板对象中
<!--数据源对象-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver"/>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test1"/>
<property name="user" value="root"/>
<property name="password" value="126433"/>
</bean>
<!--jdbc模板对象-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
测试类:
public class JdbcTemplteTest {
@Test
public void test1() throws PropertyVetoException {
ApplicationContext app = new ClassPathXmlApplicationContext("appOfDao.xml");
JdbcTemplate jt=app.getBean(JdbcTemplate.class);
int row = jt.update("insert account values (?,?)", "小朋友", 12000);
System.out.println("影响的行数"+row);
}
}
properties配置文件:
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/test1
jdbc.username=root
jdbc.password=126433
<!--加载jdbc.properties-->
<!--引入context命名空间-->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!--数据源对象-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driver}"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="user" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!--jdbc模板对象-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>