Could someone help me why it is not working,
CustomerService
package com.aop.sample;
public interface CustomerService {
void addCustomer();
String addCustomerReturnValue();
void addCustomerThrowException() throws Exception;
void addCustomerAround(String name);
}
CustomerServiceImpl
package com.aop.sample;
import org.springframework.stereotype.Component;
#Component
public class CustomerServiceImpl implements CustomerService{
public void addCustomer(){
System.out.println("addCustomer() is running ");
}
public String addCustomerReturnValue(){
System.out.println("addCustomerReturnValue() is running ");
return "abc";
}
public void addCustomerThrowException() throws Exception {
System.out.println("addCustomerThrowException() is running ");
throw new Exception("Generic Error");
}
public void addCustomerAround(String name){
System.out.println("addCustomerAround() is running, args : " + name);
}
}
LoggingAspect
package com.aop.sample;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
#Aspect
public class LoggingAspect {
#Before("execution(* com.aop.sample.CustomerService.addCustomer(..))")
public void logBefore(JoinPoint joinPoint) {
System.out.println("logBefore() is running!");
System.out.println("hijacked : " + joinPoint.getSignature().getName());
System.out.println("******");
}
}
TestRun
package com.aop.sample;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestRun {
public static void main(String[] args) {
final ClassPathXmlApplicationContext appContext = new ClassPathXmlApplicationContext(
"/META-INF/spring/app-context.xml");
CustomerService customerService = (CustomerService) appContext.getBean("customerServiceImpl");
customerService.addCustomer();
}
}
app-context.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:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<description>Example configuration to get you started.</description>
<aop:aspectj-autoproxy proxy-target-class="true"/>
<context:component-scan base-package="com.aop.sample" />
</beans>
-My Current output is -
addCustomer() is running
-Expected Out put-
logBefore() is running!
hijacked : addCustomer
******
addCustomer() is running
Kindly advice, What I'm doing wrong
Annotate your LoggingAspect class with #Component so a bean can be generated
#Aspect
#Component
public class LoggingAspect {
and registered. Alternatively, add a <bean> element in the context file for LoggingAspect.
Add this to the app-context.xml if you dont want to use annotations.
<bean name="loggingAspect" class="com.aop.sample.LogginAspect"/>
http://docs.spring.io/spring/docs/3.1.0.M1/spring-framework-reference/html/aop.html#aop-at-aspectj
Related
I am trying create an project with and without spring xml configurations.
First at all, I create my xml configuration like that:
<?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-4.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.1.xsd">
<bean id="memoryManagerProduct" class="br.com.caelum.stock.ProductManager">
<constructor-arg ref="memoryProductDAO"/>
</bean>
<bean id="memoryProductDAO" class="br.com.caelum.stock.dao.MemoryProductDAO"/>
</beans>
That I created my non XML configuration (I do not know if is right base in the fact that I do not know how invoke that)
package br.com.caelum.spring.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import br.com.caelum.stock.ProductManager;
import br.com.caelum.stock.dao.MemoryProductDAO;
import br.com.caelum.stock.dao.Persistable;
import br.com.caelum.stock.model.Product;
#Configuration
public class AppConfig {
#Bean
public Persistable<Product> memoryProductDAO(){
return new MemoryProductDAO();
}
#Bean
public ProductManager memoryProductManager(){
return new ProductManager(memoryProductDAO());
}
}
Than I created an JUnit test:
package br.com.caelum.stock;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import br.com.caelum.stock.model.Product;
public class ProductManagerTest {
private ProductManager manager;
#Test
public void testSpringXMLConfiguration() {
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:spring.xml");
manager = (ProductManager) context.getBean("memoryManagerProduct");
Product product = new Product();
product.setDescription("[Book] Spring in Action");
product.setQuantity(10);
manager.add(product);
assertThat(manager.getProducts().get(0).getDescription(), is("[Book] Spring in Action"));
}
#Test
public void testSpringWithoutXMLConfiguration() {
ApplicationContext context = ?
}
}
How can I inject the configurations that are in my AppConfig to do a similar test as in my testSpringXMLConfiguration?
There are good examples in the Spring reference guide here: http://docs.spring.io/spring/docs/current/spring-framework-reference/html/beans.html#beans-java-instantiating-container
In short, you would do this:
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
manager = (ProductManager) context.getBean("memoryManagerProduct");
However a better way of testing with Spring would be to use the spring-test support, details are here - http://docs.spring.io/spring/docs/current/spring-framework-reference/html/testing.html#integration-testing-annotations
You can do something like this with spring-test support:
#ContextConfiguration(classes = AppConfig.class)
#RunWith(SpringJUnit4ClassRunner.class)
public class ProductManagerTest {
#Autowired
private ProductManager manager;
#Test
public void testSpringXMLConfiguration() {
//use the productmanager in a test..
}
}
I have just learnt Spring Framework and have been using Spring 2.5 for this learning. I have created three beans with these classes
Food.java
package com.spring.danipetrick;
public interface Food {
void ingredients();
}
NasiGoreng.java
package com.spring.danipetrick;
public class NasiGoreng implements Food {
public NasiGoreng() {
}
public void ingredients() {
System.out.println("Rice, Coconut oil, Egg, Crackers");
}
#Override
public String toString() {
return "Nasi Goreng";
}
}
Rendang.java
package com.spring.danipetrick;
public class Rendang implements Food {
public void ingredients() {
System.out.println("Beef, Coconut milk, spices");
}
#Override
public String toString() {
return "Rendang";
}
}
PecintaKuliner.java
package com.spring.danipetrick;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
public class PecintaKuliner {
#Autowired
#Qualifier("nasigoreng")
private Food food;
#Autowired
public void setFood(Food food) {
this.food = food;
}
public Food getFood() {
return this.food;
}
public void sayMaknyus() {
System.out.println(food.toString() + " memang maknyus...");
}
}
Xml configuration, qualifier-test.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:annotation-config />
<bean id="bondan" class="com.spring.danipetrick.PecintaKuliner">
</bean>
<bean id="rendang" class="com.spring.danipetrick.Rendang"/>
<bean id="nasigoreng" class="com.spring.danipetrick.NasiGoreng" />
</beans>
Finally, class with main method is QualifierTestMain.java:
package com.spring.danipetrick;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class QualifierTestMain {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("/qualifier-test.xml");
PencintaKuliner bondan = (PencintaKuliner)context.getBean("bondan");
bondan.sayMaknyus();
}
}
When I run this project, I have an error like this
Caused by:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No
unique bean of type [com.spring.danipetrick.Food] is defined: expected
single matching bean but found 2: [rendang, nasigoreng]
Why #Qualifier annotation is not working in my case?
Both your method and field are annotated with #Autowired. As such, Spring will try to inject both. On one of the runs, it will try to inject
#Autowired
#Qualifier("nasigoreng")
private Food food;
which will work because the injection target is qualified.
The method however
#Autowired
public void setFood(Food food) {
this.food = food;
}
does not qualify the injection parameter so Spring doesn't know which bean to inject.
Change the above to
#Autowired
public void setFood(#Qualifier("nasigoreng") Food food) {
this.food = food;
}
But you should decide one or the other, field or setter injection, otherwise it is redundant and may cause errors.
I tried with Spring 4.2.4. Problem resolved just by adding
<context:annotation-config /> in configuration file.
Try only removing #Autowired from setFood() in PecintaKuliner
like
#Autowired
#Qualifier("nasigoreng")
private Food food;
public void setFood(Food food) {
this.food = food;
}
Try removing you constructor from the NasiGoreng class. It worked for me.
For others facing issue in Spring 5 -- Use xmlns based configuration..
<?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:annotation-config/>
</beans>
I have trouble with #Autowired annotation
autoWiredLocallyTest() passes
autoWireAtClassTest() failed
Here is my test cases:
/**
* Spring Autowired test.
*/
#ContextConfiguration(locations = {"classpath:applicationContext.xml"})
#RunWith(SpringJUnit4ClassRunner.class)
public class AutowiredTest {
#Autowired
private ActionBeans localBeans;
#Test
public void autoWiredLocallyTest(){
//pre-test
Assert.assertNotNull(localBeans);
}
#Test
public void autoWireAtClassTest(){
TestClazz t = new TestClazz();
boolean isAutoWiredFromClass = t.isAutowired();
Assert.assertTrue(isAutoWiredFromClass);
}
}
TestClazz is:
public class TestClazz {
#Autowired
#Qualifier("actions")
private ActionBeans tempowieBiny;
public boolean isAutowired(){
return(this.tempowieBiny!=null);
}
}
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 http://www.springframework.org/schema/beans/spring-beans.xsd">
<import resource="actions.xml" />
<import resource="datasources.xml" />
</beans>
actions.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 http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id='actions' class="net.virtalab.jsonio.configuration.actions.ActionBeans" scope="singleton">
<qualifier value="actions" />
</bean>
</beans>
What was made wrong or not done, but required to do?
I using Spring 3.2.5-RELEASE.
You are instantiating TestClazz using the new operator (TestClazz t = new TestClazz();). You need to load it from your spring context if you want the #autowired beans to be properly initialised.
Try:
#Autowired
ApplicationContext testContext;
#Test
public void autoWireAtClassTest(){
// TestClazz t = new TestClazz();
TestClazz t = (TestClazz)testContext.getBean(TestClazz.class);
boolean isAutoWiredFromClass = t.isAutowired();
Assert.assertTrue(isAutoWiredFromClass);
}
The problem here is that you're creating new TestClazz object every time. Autowire it instead:
#ContextConfiguration(locations = {"classpath:applicationContext.xml"})
#RunWith(SpringJUnit4ClassRunner.class)
public class AutowiredTest {
#Autowired
private ActionBeans localBeans;
// Added here
#Autowired
private TestClazz t;
#Test
public void autoWiredLocallyTest(){
//pre-test
Assert.assertNotNull(localBeans);
}
#Test
public void autoWireAtClassTest(){
//TestClazz t = new TestClazz(); COMMENTED OUT
boolean isAutoWiredFromClass = t.isAutowired();
Assert.assertTrue(isAutoWiredFromClass);
}
}
I'm trying to weave in code before the call of start();
This is the TestClass I want to advice:
package com.test;
public class TestClass {
public static void main(String[] args) {
new TestClass().start();
}
private void start() {
System.out.println("Test started");
}
}
This is the aspect including the advice:
package com.test;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
#Aspect
#Component
public class LogAspect {
#Before("call(void com.test.TestClass.start())")
public void logBefore(JoinPoint joinPoint) {
System.out.println("logBefore() is running");
}
}
This is my spring.xml:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd ">
<aop:aspectj-autoproxy/>
<context:annotation-config/>
<context:component-scan base-package="com.test"/>
I have also tried to name the beans explicitly in the XML like this:
<aop:aspectj-autoproxy/>
<bean id="test" class="com.test.TestClass" />
<bean id="aspect" class="com.test.LogAspect" />
This is my project setup (I'm using the Spring Tool Suite version 3.1.0):
The result is that TestClass.start is called just fine, but the advice is not applied.
What do I have to change so the advice is applied?
Thanks.
Edit: I finally got it to work:
After editing my code according to your suggestions I had a look at this tutorial. This led me to let my TestClass implement an interface. And that fixed the problem.
Here is my final setup:
The TestClass including its interface:
package com.test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
interface TestClass {
void start();
}
public class TestClassImpl implements TestClass {
public static void main(String[] args) {
ClassPathXmlApplicationContext appContext = new ClassPathXmlApplicationContext(
"Spring-Config.xml");
TestClass t1 = (TestClass) appContext.getBean("myTest");
t1.start();
}
#Override
public void start() {
System.out.println("test");
}
}
The aspect:
package com.test;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
#Aspect
public class LogAspect {
#Before("execution(void com.test.TestClass.start(..))")
public void logBefore(JoinPoint joinPoint) {
System.out.println("logging before "
+ joinPoint.getSignature().getName());
}
}
And the Spring-Config.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd ">
<aop:aspectj-autoproxy/>
<bean id="myTest" class="com.test.TestClassImpl" />
<bean id="logAspect" class="com.test.LogAspect" />
</beans>
Thanks for your help.
A call AspectJ pointcut applys when the method is called from another class. As you're calling this directly yourself you should use an execution pointcut, so change:
#Before("call(void com.test.TestClass.start())")
to
#Before("execution(void com.test.TestClass.start())")
Also let the Spring create the bean instead of creating one directly yourself.
Aside: Note, you can keep your Spring XML files separate from your source files in src/resources and they will be picked up by ClassPathXmlApplicationContext.
I want to trigger a method when a particular method from another class is invoked that is why I thought of using #Pointcut.
The code below is almost identical to the that I am coding and I don't what else I have to add.
public class OrgManagerImpl implements OrgManager {
public IOrg getOrg(String orgShortName) {
}
}
and this is the class that will should be triggered:
#Aspect
public class OrgManagerSynchronizer {
#Pointcut("execution(* com.alvin.OrgManager.getOrg(..))")
public void classMethods() {}
#Before("classMethods()")
public void synchronize(JoinPoint jp) {
//code should be executed. but does not execute.
}
}
and in my .xml this was specified:
aop:aspectj-autoproxy
What more should I add? What to do next?
Check below things.
1) Check if OrgManagerImpl is either defind as bean in context xml or it is marked as #Component & in context xml you have or that classes's package.
2) If above thing is correct then try changing pointcut as below
#Pointcut("execution(* get*(..))")
This pointcut intercepts all get methods. See if with this point cut your synchronize method is working or not. If it works then at least your spring configurations are fine. you just need to refine pointcut expression. But if this also doesn't work then there is something wrong with your spring aop configuration itself, so we can concentrate on those.
Also if this doesn't work then try to give some more info like you context xml, bean java classes etc.
Two things you need to check.
aop:aspectj-autoproxy is enabled in configuration
The Point Cut / Aspect / Target are spring bean
The below is my xml config example.
<?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">
<aop:aspectj-autoproxy/>
<context:component-scan base-package="com.techoffice"/>
<bean class="com.techoffice.example.ExampleAspect"/>
</beans>
ExampleAspect.java
package com.techoffice.example;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
#Aspect
public class ExampleAspect {
#Pointcut("execution (* com.techoffice..*(..))")
public void anyRun() {}
#Before(value="anyRun()")
public void beforeAnyRun(JoinPoint jointPoint){
System.out.println("Before " + jointPoint.getClass().getName() + "." + jointPoint.getSignature().getName());
}
#After(value="anyRun()")
public void afterAnyRun(JoinPoint jointPoint){
System.out.println("After " + jointPoint.getClass().getName() + "." + jointPoint.getSignature().getName());
}
}
HelloWorldExample
package com.techoffice.example;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Component;
#Component
public class HelloWorldExample {
public void run(){
System.out.println("run");
}
public static void main(String[] args){
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
HelloWorldExample helloWorldExample = context.getBean(HelloWorldExample.class);
helloWorldExample.run();
}
}