parent
							
								
									ec740559ed
								
							
						
					
					
						commit
						db02d38c89
					
				|  | @ -481,33 +481,38 @@ pointcut expressions by name. The following example shows three pointcut express | |||
| [source,java,indent=0,subs="verbatim,quotes",role="primary"] | ||||
| .Java | ||||
| ---- | ||||
| 	// matches if a method execution join point represents the execution of any public method | ||||
| 	@Pointcut("execution(public * *(..))") | ||||
| 	private void anyPublicOperation() {} | ||||
| 	private void anyPublicOperation() {} // <1> | ||||
| 
 | ||||
| 	// matches if a method execution is in the trading module | ||||
| 	@Pointcut("within(com.xyz.someapp.trading..*)") | ||||
| 	private void inTrading() {} | ||||
| 	private void inTrading() {} // <2> | ||||
| 
 | ||||
| 	// matches if a method execution represents any public method in the trading module | ||||
| 	@Pointcut("anyPublicOperation() && inTrading()") | ||||
| 	private void tradingOperation() {} | ||||
| 	private void tradingOperation() {} // <3> | ||||
| ---- | ||||
| <1> `anyPublicOperation` matches if a method execution join point represents the execution | ||||
| of any public method. | ||||
| <2> `inTrading` matches if a method execution is in the trading module. | ||||
| <3> `tradingOperation` matches if a method execution represents any public method in the | ||||
| trading module. | ||||
| 
 | ||||
| [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] | ||||
| .Kotlin | ||||
| ---- | ||||
| 	// matches if a method execution join point represents the execution of any public method. | ||||
| 	@Pointcut("execution(public * *(..))") | ||||
| 	private fun anyPublicOperation() {} | ||||
| 	private fun anyPublicOperation() {} // <1> | ||||
| 
 | ||||
| 	// matches if a method execution is in the trading module | ||||
| 	@Pointcut("within(com.xyz.someapp.trading..*)") | ||||
| 	private fun inTrading() {} | ||||
| 	private fun inTrading() {} // <2> | ||||
| 
 | ||||
| 	// matches if a method execution represents any public method in the trading module | ||||
| 	@Pointcut("anyPublicOperation() && inTrading()") | ||||
| 	private fun tradingOperation() {} | ||||
| 	private fun tradingOperation() {} // <3> | ||||
| ---- | ||||
| <1> `anyPublicOperation` matches if a method execution join point represents the execution | ||||
| of any public method. | ||||
| <2> `inTrading` matches if a method execution is in the trading module. | ||||
| <3> `tradingOperation` matches if a method execution represents any public method in the | ||||
| trading module. | ||||
| 
 | ||||
| It is a best practice to build more complex pointcut expressions out of smaller named | ||||
| components, as shown earlier. When referring to pointcuts by name, normal Java visibility | ||||
|  |  | |||
|  | @ -860,14 +860,10 @@ we can parse our custom XML content, as you can see in the following example: | |||
| 
 | ||||
| 	import java.text.SimpleDateFormat; | ||||
| 
 | ||||
| 	// We use the Spring-provided AbstractSingleBeanDefinitionParser to handle a lot of | ||||
| 	// the basic grunt work of creating a single BeanDefinition. | ||||
| 	public class SimpleDateFormatBeanDefinitionParser extends AbstractSingleBeanDefinitionParser { | ||||
| 	public class SimpleDateFormatBeanDefinitionParser extends AbstractSingleBeanDefinitionParser { // <1> | ||||
| 
 | ||||
| 		protected Class getBeanClass(Element element) { | ||||
| 			// We supply the AbstractSingleBeanDefinitionParser superclass with the type that our | ||||
| 			// single BeanDefinition represents. | ||||
| 			return SimpleDateFormat.class; | ||||
| 			return SimpleDateFormat.class; // <2> | ||||
| 		} | ||||
| 
 | ||||
| 		protected void doParse(Element element, BeanDefinitionBuilder bean) { | ||||
|  | @ -884,6 +880,11 @@ we can parse our custom XML content, as you can see in the following example: | |||
| 
 | ||||
| 	} | ||||
| ---- | ||||
| <1> We use the Spring-provided `AbstractSingleBeanDefinitionParser` to handle a lot of | ||||
| the basic grunt work of creating a single `BeanDefinition`. | ||||
| <2> We supply the `AbstractSingleBeanDefinitionParser` superclass with the type that our | ||||
| single `BeanDefinition` represents. | ||||
| 
 | ||||
| [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] | ||||
| .Kotlin | ||||
| ---- | ||||
|  | @ -896,13 +897,9 @@ we can parse our custom XML content, as you can see in the following example: | |||
| 
 | ||||
| 	import java.text.SimpleDateFormat | ||||
| 
 | ||||
| 	// We use the Spring-provided AbstractSingleBeanDefinitionParser to handle a lot of | ||||
| 	// the basic grunt work of creating a single BeanDefinition. | ||||
| 	class SimpleDateFormatBeanDefinitionParser : AbstractSingleBeanDefinitionParser() { | ||||
| 	class SimpleDateFormatBeanDefinitionParser : AbstractSingleBeanDefinitionParser() { // <1> | ||||
| 
 | ||||
| 		override fun getBeanClass(element: Element): Class<*>? { | ||||
| 			// We supply the AbstractSingleBeanDefinitionParser superclass with the type that our | ||||
| 			// single BeanDefinition represents. | ||||
| 		override fun getBeanClass(element: Element): Class<*>? { // <2> | ||||
| 			return SimpleDateFormat::class.java | ||||
| 		} | ||||
| 
 | ||||
|  | @ -919,6 +916,11 @@ we can parse our custom XML content, as you can see in the following example: | |||
| 		} | ||||
| 	} | ||||
| ---- | ||||
| <1> We use the Spring-provided `AbstractSingleBeanDefinitionParser` to handle a lot of | ||||
| the basic grunt work of creating a single `BeanDefinition`. | ||||
| <2> We supply the `AbstractSingleBeanDefinitionParser` superclass with the type that our | ||||
| single `BeanDefinition` represents. | ||||
| 
 | ||||
| 
 | ||||
| In this simple case, this is all that we need to do. The creation of our single | ||||
| `BeanDefinition` is handled by the `AbstractSingleBeanDefinitionParser` superclass, as | ||||
|  |  | |||
|  | @ -5599,24 +5599,27 @@ following example: | |||
| 	public class MovieRecommender { | ||||
| 
 | ||||
| 		@Autowired | ||||
| 		@Offline | ||||
| 		@Offline // <1> | ||||
| 		private MovieCatalog offlineCatalog; | ||||
| 
 | ||||
| 		// ... | ||||
| 	} | ||||
| ---- | ||||
| <1> This line adds the `@Offline` annotation. | ||||
| 
 | ||||
| [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] | ||||
| .Kotlin | ||||
| ---- | ||||
| class MovieRecommender { | ||||
| 
 | ||||
| 	@Autowired | ||||
| 	@Offline | ||||
| 	@Offline // <1> | ||||
| 	private lateinit var offlineCatalog: MovieCatalog | ||||
| 
 | ||||
| 	// ... | ||||
| } | ||||
| ---- | ||||
| <1> This line adds the `@Offline` annotation. | ||||
| 
 | ||||
| Now the bean definition only needs a qualifier `type`, as shown in the following example: | ||||
| 
 | ||||
|  | @ -5915,21 +5918,24 @@ as demonstrated in the following example: | |||
| 
 | ||||
| 		private MovieFinder movieFinder; | ||||
| 
 | ||||
| 		@Resource(name="myMovieFinder") // This line injects a @Resource | ||||
| 		@Resource(name="myMovieFinder") // <1> | ||||
| 		public void setMovieFinder(MovieFinder movieFinder) { | ||||
| 			this.movieFinder = movieFinder; | ||||
| 		} | ||||
| 	} | ||||
| ---- | ||||
| <1> This line injects a `@Resource`. | ||||
| 
 | ||||
| [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] | ||||
| .Kotlin | ||||
| ---- | ||||
| class SimpleMovieLister { | ||||
| 
 | ||||
| 	@Resource(name="myMovieFinder") // This line injects a @Resource | ||||
| 	@Resource(name="myMovieFinder") // <1> | ||||
| 	private lateinit var movieFinder:MovieFinder | ||||
| } | ||||
| ---- | ||||
| <1> This line injects a `@Resource`. | ||||
| 
 | ||||
| 
 | ||||
| If no name is explicitly specified, the default name is derived from the field name or | ||||
|  | @ -5986,10 +5992,8 @@ named "customerPreferenceDao" and then falls back to a primary type match for th | |||
| 		@Resource | ||||
| 		private CustomerPreferenceDao customerPreferenceDao; | ||||
| 
 | ||||
| 		// The context field is injected based on the known resolvable dependency | ||||
| 		// type: ApplicationContext | ||||
| 		@Resource | ||||
| 		private ApplicationContext context; | ||||
| 		private ApplicationContext context; // <1> | ||||
| 
 | ||||
| 		public MovieRecommender() { | ||||
| 		} | ||||
|  | @ -5997,6 +6001,9 @@ named "customerPreferenceDao" and then falls back to a primary type match for th | |||
| 		// ... | ||||
| 	} | ||||
| ---- | ||||
| <1> The `context` field is injected based on the known resolvable dependency type: | ||||
| `ApplicationContext`. | ||||
| 
 | ||||
| [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] | ||||
| .Kotlin | ||||
| ---- | ||||
|  | @ -6005,14 +6012,15 @@ named "customerPreferenceDao" and then falls back to a primary type match for th | |||
| 		@Resource | ||||
| 		private lateinit var customerPreferenceDao: CustomerPreferenceDao | ||||
| 
 | ||||
| 		// The context field is injected based on the known resolvable dependency | ||||
| 		// type: ApplicationContext | ||||
| 
 | ||||
| 		@Resource | ||||
| 		private lateinit var context: ApplicationContext | ||||
| 		private lateinit var context: ApplicationContext // <1> | ||||
| 
 | ||||
| 		// ... | ||||
| 	} | ||||
| ---- | ||||
| <1> The `context` field is injected based on the known resolvable dependency type: | ||||
| `ApplicationContext`. | ||||
| 
 | ||||
| [[beans-value-annotations]] | ||||
| === Using `@Value` | ||||
|  | @ -6341,24 +6349,27 @@ is meta-annotated with `@Component`, as the following example shows: | |||
| 	@Target(ElementType.TYPE) | ||||
| 	@Retention(RetentionPolicy.RUNTIME) | ||||
| 	@Documented | ||||
| 	@Component // Causes @Service to be treated in the same way as @Component | ||||
| 	@Component // <1> | ||||
| 	public @interface Service { | ||||
| 
 | ||||
| 		// ... | ||||
| 	} | ||||
| ---- | ||||
| <1> The `Component` causes `@Service` to be treated in the same way as `@Component`. | ||||
| 
 | ||||
| [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] | ||||
| .Kotlin | ||||
| ---- | ||||
| 	@Target(AnnotationTarget.TYPE) | ||||
| 	@Retention(AnnotationRetention.RUNTIME) | ||||
| 	@MustBeDocumented | ||||
| 	@Component // Causes @Service to be treated in the same way as @Component | ||||
| 	@Component // <1> | ||||
| 	annotation class Service { | ||||
| 
 | ||||
| 		// ... | ||||
| 	} | ||||
| ---- | ||||
| <1> The `Component` causes `@Service` to be treated in the same way as `@Component`. | ||||
| 
 | ||||
| You can also combine meta-annotations to create "`composed annotations`". For example, | ||||
| the `@RestController` annotation from Spring MVC is composed of `@Controller` and | ||||
|  | @ -7779,20 +7790,23 @@ To enable component scanning, you can annotate your `@Configuration` class as fo | |||
| .Java | ||||
| ---- | ||||
| 	@Configuration | ||||
| 	@ComponentScan(basePackages = "com.acme") // This annotation enables component scanning | ||||
| 	@ComponentScan(basePackages = "com.acme") // <1> | ||||
| 	public class AppConfig  { | ||||
| 		... | ||||
| 	} | ||||
| ---- | ||||
| <1> This annotation enables component scanning. | ||||
| 
 | ||||
| [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] | ||||
| .Kotlin | ||||
| ---- | ||||
| 	@Configuration | ||||
| 	@ComponentScan(basePackages = ["com.acme"]) // This annotation enables component scanning | ||||
| 	@ComponentScan(basePackages = ["com.acme"]) // <1> | ||||
| 	class AppConfig  { | ||||
| 		// ... | ||||
| 	} | ||||
| ---- | ||||
| <1> This annotation enables component scanning. | ||||
| 
 | ||||
| 
 | ||||
| [TIP] | ||||
|  | @ -9655,7 +9669,7 @@ the following example shows: | |||
| 	public class AppConfig { | ||||
| 
 | ||||
| 		@Bean("dataSource") | ||||
| 		@Profile("development") // The standaloneDataSource method is available only in the development profile | ||||
| 		@Profile("development") // <1> | ||||
| 		public DataSource standaloneDataSource() { | ||||
| 			return new EmbeddedDatabaseBuilder() | ||||
| 				.setType(EmbeddedDatabaseType.HSQL) | ||||
|  | @ -9665,13 +9679,16 @@ the following example shows: | |||
| 		} | ||||
| 
 | ||||
| 		@Bean("dataSource") | ||||
| 		@Profile("production") // The jndiDataSource method is available only in the production profile | ||||
| 		@Profile("production") // <2> | ||||
| 		public DataSource jndiDataSource() throws Exception { | ||||
| 			Context ctx = new InitialContext(); | ||||
| 			return (DataSource) ctx.lookup("java:comp/env/jdbc/datasource"); | ||||
| 		} | ||||
| 	} | ||||
| ---- | ||||
| <1> The `standaloneDataSource` method is available only in the `development` profile. | ||||
| <2> The `jndiDataSource` method is available only in the `production` profile. | ||||
| 
 | ||||
| [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] | ||||
| .Kotlin | ||||
| ---- | ||||
|  | @ -9679,7 +9696,7 @@ the following example shows: | |||
| 	class AppConfig { | ||||
| 
 | ||||
| 		@Bean("dataSource") | ||||
| 		@Profile("development") // The standaloneDataSource method is available only in the development profile | ||||
| 		@Profile("development") // <1> | ||||
| 		fun standaloneDataSource(): DataSource { | ||||
| 			return EmbeddedDatabaseBuilder() | ||||
| 					.setType(EmbeddedDatabaseType.HSQL) | ||||
|  | @ -9689,11 +9706,13 @@ the following example shows: | |||
| 		} | ||||
| 
 | ||||
| 		@Bean("dataSource") | ||||
| 		@Profile("production") // The jndiDataSource method is available only in the production profile | ||||
| 		@Profile("production") // <2> | ||||
| 		fun jndiDataSource() = | ||||
| 			InitialContext().lookup("java:comp/env/jdbc/datasource") as DataSource | ||||
| 	} | ||||
| ---- | ||||
| <1> The `standaloneDataSource` method is available only in the `development` profile. | ||||
| <2> The `jndiDataSource` method is available only in the `production` profile. | ||||
| 
 | ||||
| [NOTE] | ||||
| ==== | ||||
|  |  | |||
|  | @ -69,16 +69,19 @@ The following code introduces the SpEL API to evaluate the literal string expres | |||
| .Java | ||||
| ---- | ||||
| 	ExpressionParser parser = new SpelExpressionParser(); | ||||
| 	Expression exp = parser.parseExpression("'Hello World'"); // The value of the message variable is 'Hello World' | ||||
| 	Expression exp = parser.parseExpression("'Hello World'"); // <1> | ||||
| 	String message = (String) exp.getValue(); | ||||
| ---- | ||||
| <1> The value of the message variable is `'Hello World'`. | ||||
| 
 | ||||
| [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] | ||||
| .Kotlin | ||||
| ---- | ||||
| 	val parser = SpelExpressionParser() | ||||
| 	val exp = parser.parseExpression("'Hello World'") // The value of the message variable is 'Hello World' | ||||
| 	val exp = parser.parseExpression("'Hello World'") // <1> | ||||
| 	val message = exp.value as String | ||||
| ---- | ||||
| <1> The value of the message variable is `'Hello World'`. | ||||
| 
 | ||||
| 
 | ||||
| The SpEL classes and interfaces you are most likely to use are located in the | ||||
|  | @ -100,18 +103,19 @@ In the following example of method invocation, we call the `concat` method on th | |||
| .Java | ||||
| ---- | ||||
| 	ExpressionParser parser = new SpelExpressionParser(); | ||||
| 	Expression exp = parser.parseExpression("'Hello World'.concat('!')"); | ||||
| 	// The value of message is now 'Hello World!' | ||||
| 	Expression exp = parser.parseExpression("'Hello World'.concat('!')"); // <1> | ||||
| 	String message = (String) exp.getValue(); | ||||
| ---- | ||||
| <1> The value of `message` is now 'Hello World!'. | ||||
| 
 | ||||
| [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] | ||||
| .Kotlin | ||||
| ---- | ||||
| 	val parser = SpelExpressionParser() | ||||
| 	val exp = parser.parseExpression("'Hello World'.concat('!')") | ||||
| 	// The value of message is now 'Hello World!' | ||||
| 	val exp = parser.parseExpression("'Hello World'.concat('!')") // <1> | ||||
| 	val message = exp.value as String | ||||
| ---- | ||||
| <1> The value of `message` is now 'Hello World!'. | ||||
| 
 | ||||
| The following example of calling a JavaBean property calls the `String` property `Bytes`: | ||||
| 
 | ||||
|  | @ -121,18 +125,21 @@ The following example of calling a JavaBean property calls the `String` property | |||
| 	ExpressionParser parser = new SpelExpressionParser(); | ||||
| 
 | ||||
| 	// invokes 'getBytes()' | ||||
| 	Expression exp = parser.parseExpression("'Hello World'.bytes"); // This line converts the literal to a byte array | ||||
| 	Expression exp = parser.parseExpression("'Hello World'.bytes"); // <1> | ||||
| 	byte[] bytes = (byte[]) exp.getValue(); | ||||
| ---- | ||||
| <1> This line converts the literal to a byte array. | ||||
| 
 | ||||
| [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] | ||||
| .Kotlin | ||||
| ---- | ||||
| 	val parser = SpelExpressionParser() | ||||
| 
 | ||||
| 	// invokes 'getBytes()' | ||||
| 	val exp = parser.parseExpression("'Hello World'.bytes") // This line converts the literal to a byte array | ||||
| 	val exp = parser.parseExpression("'Hello World'.bytes") // <1> | ||||
| 	val bytes = exp.value as ByteArray | ||||
| ---- | ||||
| <1> This line converts the literal to a byte array. | ||||
| 
 | ||||
| SpEL also supports nested properties by using the standard dot notation (such as | ||||
| `prop1.prop2.prop3`) and also the corresponding setting of property values. | ||||
|  | @ -146,18 +153,21 @@ The following example shows how to use dot notation to get the length of a liter | |||
| 	ExpressionParser parser = new SpelExpressionParser(); | ||||
| 
 | ||||
| 	// invokes 'getBytes().length' | ||||
| 	Expression exp = parser.parseExpression("'Hello World'.bytes.length"); // 'Hello World'.bytes.length gives the length of the literal. | ||||
| 	Expression exp = parser.parseExpression("'Hello World'.bytes.length"); // <1> | ||||
| 	int length = (Integer) exp.getValue(); | ||||
| ---- | ||||
| <1> `'Hello World'.bytes.length` gives the length of the literal. | ||||
| 
 | ||||
| [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] | ||||
| .Kotlin | ||||
| ---- | ||||
| 	val parser = SpelExpressionParser() | ||||
| 
 | ||||
| 	// invokes 'getBytes().length' | ||||
| 	val exp = parser.parseExpression("'Hello World'.bytes.length") // 'Hello World'.bytes.length gives the length of the literal. | ||||
| 	val exp = parser.parseExpression("'Hello World'.bytes.length") // <1> | ||||
| 	val length = exp.value as Int | ||||
| ---- | ||||
| <1> `'Hello World'.bytes.length` gives the length of the literal. | ||||
| 
 | ||||
| The String's constructor can be called instead of using a string literal, as the following | ||||
| example shows: | ||||
|  | @ -166,18 +176,19 @@ example shows: | |||
| .Java | ||||
| ---- | ||||
| 	ExpressionParser parser = new SpelExpressionParser(); | ||||
| 	// Construct a new String from the literal and make it be upper case | ||||
| 	Expression exp = parser.parseExpression("new String('hello world').toUpperCase()"); | ||||
| 	String message = exp.getValue(String.class); | ||||
| ---- | ||||
| <1> Construct a new `String` from the literal and make it be upper case. | ||||
| 
 | ||||
| [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] | ||||
| .Kotlin | ||||
| ---- | ||||
| 	val parser = SpelExpressionParser() | ||||
| 	// Construct a new String from the literal and make it be upper case | ||||
| 	val exp = parser.parseExpression("new String('hello world').toUpperCase()") | ||||
| 	val message = exp.getValue(String::class.java) | ||||
| ---- | ||||
| <1> Construct a new `String` from the literal and make it be upper case. | ||||
| 
 | ||||
| 
 | ||||
| Note the use of the generic method: `public <T> T getValue(Class<T> desiredResultType)`. | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue